在UWP中使用StreamSocket时如何知道套接字连接是否仍然存在?

时间:2016-05-16 17:13:29

标签: c# sockets win-universal-app

我使用StreamSocket连接到套接字服务器,我使用无限循环来读取数据。每条数据都以'\n\n'结尾。该片段如下所示。但是,我无法知道套接字是否仍然存在,并且每次服务器关闭连接时,ReadAsync()都会抛出异常。如何在连接关闭时收到通知?

public async Task<string> ReadData() {
    StreamReader reader = new StreamReader(socket.InputStream.AsStreamForRead());
    char[] ch = new char[65536];
    int i = 0;
    while (IsConnected) {
        await reader.ReadAsync(ch, i++, 1);
        if (i > 1 && ch[i - 1] == '\n' && ch[i - 2] == '\n') break;
    }
    return new StringBuilder().Append(ch, 0, i - 2).ToString();
}

2 个答案:

答案 0 :(得分:1)

  

每次服务器关闭连接时,ReadAsync()都会抛出异常。

大多数服务器都应该如此。 TCP / IP有一个相当昂贵的四部分握手来优雅地关闭连接,但从服务器的角度来看,等待回收这些资源需要很长时间。所以,很多服务器只是“猛烈抨击”。连接关闭,导致SocketError.ConnectionReset错误。

正如我在socket error handling博客文章中描述的那样,如果沟通状态是这样的,你会考虑一个优雅的关闭&#34;在那时适当,那么你也应该在同一点接受ConnectionReset的异常。 (在您的情况下,适当的&#34;关闭&#34;点是指消息是否已使用\n\n完成。)

  

如何在连接关闭时收到通知?

您将获得ConnectionReset例外(如果它突然关闭),或者您的ReadAsync将返回0(如果它正常关闭)。

...然而

  

如何知道套接字连接是否仍然存在?

只有一种可靠的方法可以检测套接字连接是否仍然可行:数据写入其中。我在half-open problem上的博文中详细介绍了这一点。

由于套接字通信中这个相当有趣的怪癖,像while (IsConnected)这样的代码是一种反模式。相反,您需要有一个定期轮询循环,基于计时器将数据发送到另一方。

P.S。如果可能的话,使用SignalR而不是原始套接字。他们为你做了所有艰难的事情。

答案 1 :(得分:0)

  

每次服务器关闭连接时,ReadAsync()都会抛出异常。

抛出异常是因为发生非正常断开连接。因此,在关闭服务器端的连接之前,确保套接字上存在没有任何挂起的读取或写入操作,那么应该没有异常。您可以参考StreamSocket class的备注部分了解更多详情。

  

如何在连接关闭时收到通知?

另一方可以检测到正常的套接字闭包为0长度读取。也就是说,它只是像常规的流末端一样。 Here是一个类似的帖子供您参考。

因此,您可以使用以下代码检查您的方案中是否已关闭连接:

public async Task<string> ReadData()
{
    StreamReader reader = new StreamReader(socket.InputStream.AsStreamForRead());
    char[] ch = new char[65536];
    int i = 0;
    while (true)
    {
        await reader.ReadAsync(ch, i++, 1);
        // break when the connection is closed or data ends with '\n\n'
        if (ch[i - 1] == '\0' || (i > 1 && ch[i - 1] == '\n' && ch[i - 2] == '\n')) break;
    }

    if (ch[i - 1] == '\0')
    {
        // do something here when the connection is closed
    }
    else
    {
        return new StringBuilder().Append(ch, 0, i - 2).ToString();
    }
}

以下是我验证的整个方法:

class FunctionDictionary
{
    /// <summary>
    /// Internal dictionary that will store the function delegates as Object.
    /// </summary>
    private Dictionary<string, Object> m_Map = new Dictionary<string, object>();

    /// <summary>
    /// Add method to dictionary for specified key. Encapsulated method has no parameters.
    /// </summary>
    public void Add<TResult>(string key, Func<TResult> function) 
    {
        m_Map.Add(key, function);
    }

    /// <summary>
    /// Get method for specified key. Encapsulated method has no parameters.
    /// </summary>
    public Func<TResult> Function<TResult>(string key)
    {
        return (Func<TResult>)m_Map[key];
    }

    /// <summary>
    /// Add method to dictionary for specified key. Encapsulated method has one parameters.
    /// </summary>
    public void Add<T1, TResult>(string key, Func<T1, TResult> function)
    {
        m_Map.Add(key, function);
    }

    /// <summary>
    /// Get method for specified key. Encapsulated method has one parameters.
    /// </summary>
    public Func<T, TResult> Function<T, TResult>(string key)
    {
        return (Func<T, TResult>)m_Map[key];
    }


    public void Add<T1, T2, TResult>(string key, Func<T1, T2, TResult> function)
    {
        m_Map.Add(key, function);
    }
    public void Add<T1, T2, T3, TResult>(string key, Func<T1, T2, T3, TResult> function)
    {
        m_Map.Add(key, function);
    }
    public void Add<T1, T2, T3, T4, TResult>(string key, Func<T1, T2, T3, T4, TResult> function)
    {
        m_Map.Add(key, function);
    }
    public void Add<T1, T2, T3, T4, T5, TResult>(string key, Func<T1, T2, T3, T4, T5, TResult> function)
    {
        m_Map.Add(key, function);
    }
    public void Add<T1, T2, T3, T4, T5, T6, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, TResult> function)
    {
        m_Map.Add(key, function);
    }
    public void Add<T1, T2, T3, T4, T5, T6, T7, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, T7, TResult> function)
    {
        m_Map.Add(key, function);
    }
    public void Add<T1, T2, T3, T4, T5, T6, T7, T8, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, T7, T8, TResult> function)
    {
        m_Map.Add(key, function);
    }
    public void Add<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult> function)
    {
        m_Map.Add(key, function);
    }
    public void Add<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult> function)
    {
        m_Map.Add(key, function);
    }
    public void Add<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TResult> function)
    {
        m_Map.Add(key, function);
    }
    public void Add<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TResult> function)
    {
        m_Map.Add(key, function);
    }
    public void Add<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TResult> function)
    {
        m_Map.Add(key, function);
    }
    public void Add<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TResult> function)
    {
        m_Map.Add(key, function);
    }
    public void Add<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, TResult> function)
    {
        m_Map.Add(key, function);
    }
    public void Add<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult> function)
    {
        m_Map.Add(key, function);
    }


    public Object this[string key]
    {
        get
        {
            return m_Map[key];
        }
    }

    public Func<T1, T2, TResult> Function<T1, T2, TResult>(string key)
    {
        return (Func<T1, T2, TResult>)m_Map[key];
    }
    public Func<T1, T2, T3, TResult> Function<T1, T2, T3, TResult>(string key)
    {
        return (Func<T1, T2, T3, TResult>)m_Map[key];
    }
    public Func<T1, T2, T3, T4, TResult> Function<T1, T2, T3, T4, TResult>(string key)
    {
        return (Func<T1, T2, T3, T4, TResult>)m_Map[key];
    }
    public Func<T1, T2, T3, T4, T5, TResult> Function<T1, T2, T3, T4, T5, TResult>(string key)
    {
        return (Func<T1, T2, T3, T4, T5, TResult>)m_Map[key];
    }
    public Func<T1, T2, T3, T4, T5, T6, TResult> Function<T1, T2, T3, T4, T5, T6, TResult>(string key)
    {
        return (Func<T1, T2, T3, T4, T5, T6, TResult>)m_Map[key];
    }
    public Func<T1, T2, T3, T4, T5, T6, T7, TResult> Function<T1, T2, T3, T4, T5, T6, T7, TResult>(string key)
    {
        return (Func<T1, T2, T3, T4, T5, T6, T7, TResult>)m_Map[key];
    }
    public Func<T1, T2, T3, T4, T5, T6, T7, T8, TResult> Function<T1, T2, T3, T4, T5, T6, T7, T8, TResult>(string key)
    {
        return (Func<T1, T2, T3, T4, T5, T6, T7, T8, TResult>)m_Map[key];
    }
    public Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult> Function<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult>(string key)
    {
        return (Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult>)m_Map[key];
    }
    public Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult> Function<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult>(string key)
    {
        return (Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult>)m_Map[key];
    }
    public Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TResult> Function<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TResult>(string key)
    {
        return (Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TResult>)m_Map[key];
    }
    public Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TResult> Function<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TResult>(string key)
    {
        return (Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TResult>)m_Map[key];
    }
    public Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TResult> Function<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TResult>(string key)
    {
        return (Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TResult>)m_Map[key];
    }
    public Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TResult> Function<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TResult>(string key)
    {
        return (Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TResult>)m_Map[key];
    }
    public Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, TResult> Function<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, TResult>(string key)
    {
        return (Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, TResult>)m_Map[key];
    }
    public Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult> Function<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult>(string key)
    {
        return (Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult>)m_Map[key];
    }

}