我试图教育自己从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 */
}
}
我在代码中标记了三个点,程序说“有些东西出了问题,没有必要继续下去”。
'本地断开连接'并非完全错误,当我在本地关闭套接字时会发生这种情况,这是在正常情况下退出循环的唯一方法。我认为其他任何事情都不会导致这种情况发生,所以我认为我可以安全地接受这个例外。
两个'远程断开连接'积分是我不确定的。我知道如果远程终止连接,ReadAsync将返回0(A),但在某些情况下似乎也会触发IOException。如果我的远程客户端是C#控制台,那么关闭套接字似乎会使A' A'发生了,并关闭控制台窗口似乎是' B' B' B'发生。我不确定我理解这些场景之间的区别是什么?
最后,这是一个普遍的问题,但是这些代码或我的上述假设是否有任何明显的错误?
感谢。
编辑:响应我使用ObjectDisposedException中止循环:
这就是我的停止'方法看起来像(与上面相同的类):
public void Stop()
{
this.tcp.Close();
}
这导致待处理的' ReadAsync'与ObjectDisposedException除外。 AFAIK没有任何其他方法可以中止这一点。将此更改为:
public void Stop()
{
this.tcp.Client.Shutdown(SocketShutdown.Both);
}
似乎没有对待处理的电话做任何事情,它只是继续等待。
答案 0 :(得分:2)
当NetworkStream
返回0时,这表示套接字已从远程方收到断开连接数据包。这就是网络连接的结束方式。
关闭连接的正确方法(特别是在进行全双工对话时)是拨打socket.Shutdown(SocketShutdown.Send)
并让远程方有时间关闭其发送频道。这可确保您收到任何待处理数据,而不是关闭连接。 ObjectDisposedException
永远不应成为正常申请流程的一部分。
抛出的任何异常都表明出现了问题,我认为可以说你不能再依赖当前的连接了。
TL; DR
我没有看到您的代码有任何问题,但(特别是在全双工通信中)我会关闭发送通道并等待0字节数据包以防止默认接收ObjectDisposedException
:
使用tcp.Shutdown(SocketShutdown.Send)
告诉要断开连接的远程方
您的循环可能仍会收到远程方正在发送的数据
如果一切正常,你的循环将接收一个0字节的数据包,表明远程方正在断开连接
循环以正确的方式终止
如果你没有收到0字节的数据包,你可能想在一段时间后决定处理套接字