NetworkStream 异常和 return 代码

NetworkStream exceptions and return codes

我正在努力自学从 NetworkStream 中读取的复杂性,并了解问题可能发生的各种方式。我有以下代码:

    public async Task ReceiveAll()
    {
        var ns = this.tcp.GetStream();
        var readBuffer = new byte[1000];
        while (true)
        {
            int bytesRead;
            try
            {
                bytesRead = await ns.ReadAsync(readBuffer, 0, readBuffer.Length);
                if (bytesRead == 0)
                {
                    // Remote disconnection A?
                    break;
                }
            }
            catch (IOException)
            {
                // Remote disconnection B?
                break;
            }
            catch (ObjectDisposedException)
            {
                // Local disconnection?
                break;
            }

            /*Do something with readBuffer */
        }
    }

我在代码中标记了三个点,其中程序显示 'something has gone awry, there is no point continuing'。

'Local disconnection' 并没有什么问题,当我在本地关闭套接字时会发生这种情况,这是正常情况下退出循环的唯一方法。我认为没有其他原因会导致这种情况,所以我认为我可以安全地吞下这个例外。

这两点'Remote disconnection'是我不确定的地方。我知道如果连接被远程终止 (A),ReadAsync 将 return 0,但 IOException 在某些情况下似乎也会触发。如果我的远程客户端是 C# 控制台,那么关闭套接字似乎会使 'A' 发生,而关闭控制台 window 似乎会使 'B' 发生。我不确定我是否理解这些场景之间的区别?

最后,问一个一般性的问题,但是这段代码或我的上述假设有什么明显的错误吗?

谢谢。

编辑:响应我使用 ObjectDisposedException 退出循环:

这就是我的 'Stop' 方法的样子(来自与上面相同的 class):

    public void Stop()
    {
        this.tcp.Close();
    }

这会导致挂起的 'ReadAsync' 异常异常。 AFAIK 没有任何其他方法可以中止它。将其更改为:

    public void Stop()
    {
        this.tcp.Client.Shutdown(SocketShutdown.Both);
    }

似乎没有对挂起的呼叫做任何事情,它只是继续等待。

NetworkStream returns 0时,表示socket收到了对方发来的disconnect包。这就是网络连接应该如何结束。

关闭连接的正确方法(尤其是在全双工对话中)是调用 socket.Shutdown(SocketShutdown.Send) 并给远程方一些时间来关闭他们的发送通道。这可以确保您收到任何待处理的数据,而不是关闭连接。 ObjectDisposedException 永远不应成为正常申请流程的一部分。

抛出的任何异常都表明出现了问题,我认为可以肯定地说您不能再依赖当前连接。

TL;DR

我没有发现您的代码有任何问题,但是(尤其是在全双工通信中)我会关闭发送通道并等待 0 字节数据包以防止接收 ObjectDisposedExceptions默认:

  1. 使用tcp.Shutdown(SocketShutdown.Send)告诉对方你想断开连接

  2. 您的循环可能仍会收到远程方正在发送的数据

  3. 如果一切正常,你的循环将收到一个 0 字节的数据包,表明对方正在断开连接

  4. 循环以正确的方式终止

  5. 如果您还没有收到 0 字节数据包,您可能想在一定时间后决定处理套接字