C# 网络流异常和返回代码
我试图让自己了解从网络流中阅读的复杂性,并了解问题可能发生的各种方式。我有以下代码:C# 网络流异常和返回代码,c#,async-await,tcpclient,networkstream,C#,Async Await,Tcpclient,Networkstream,我试图让自己了解从网络流中阅读的复杂性,并了解问题可能发生的各种方式。我有以下代码: public异步任务ReceiveAll() { var ns=this.tcp.GetStream(); var readBuffer=新字节[1000]; while(true) { int字节读取; 尝试 { bytesRead=wait ns.ReadAsync(readBuffer,0,readBuffer.Length); 如果(字节读==0) { //远程断开A? 打破 } } 捕获(IOExce
public异步任务ReceiveAll()
{
var ns=this.tcp.GetStream();
var readBuffer=新字节[1000];
while(true)
{
int字节读取;
尝试
{
bytesRead=wait ns.ReadAsync(readBuffer,0,readBuffer.Length);
如果(字节读==0)
{
//远程断开A?
打破
}
}
捕获(IOException)
{
//远程断开B?
打破
}
捕获(ObjectDisposedException)
{
//本地断开?
打破
}
/*用readBuffer做些什么*/
}
}
我在代码中标记了三个点,其中程序说“有些地方出了问题,没有继续下去的意义”
“本地断开”并不是什么问题,它会发生在我本地关闭套接字时,这是正常情况下退出循环的唯一方法。我不认为其他任何原因会导致这种情况,所以我认为我可以安全地接受这个例外
这两个“远程断开”点是我不确定的。我知道如果远程终止连接(A),ReadAsync将返回0,但在某些情况下,IOException似乎也会触发。如果我的远程客户端是一个C#控制台,那么关闭套接字似乎使“a”发生,关闭控制台窗口似乎使“B”发生。我不确定我是否理解这些场景之间的区别
最后,是一个一般性的问题,但这段代码或我的上述假设是否有明显的错误
谢谢
编辑:为了响应我使用ObjectDisposedException中止循环外的操作:
这就是我的“Stop”方法的样子(来自与上面相同的类):
这会导致挂起的“ReadAsync”与ObjectDisposedException一起异常。好了,没有其他方法可以中止这个。将此更改为:
public void Stop()
{
this.tcp.Client.Shutdown(SocketShutdown.Both);
}
实际上对挂起的调用似乎没有做任何处理,它只是继续等待。当
NetworkStream
返回0时,这意味着套接字已收到来自远程方的断开连接数据包。这就是网络连接应该结束的方式
关闭连接的正确方法(尤其是在全双工对话中)是调用socket.Shutdown(SocketShutdown.Send)
,并给远程方一些时间关闭其发送通道。这可以确保您收到任何挂起的数据,而不是关闭连接ObjectDisposedException
不应成为正常应用程序流的一部分
抛出的任何异常都表明出现了问题,我认为可以肯定地说,您不能再依赖当前连接
TL;DR
我看不出您的代码有任何问题,但(特别是在全双工通信中)我会关闭发送通道并等待0字节的数据包,以防止默认情况下接收ObjectDisposedException
s:
tcp.Shutdown(SocketShutdown.Send)
通知远程方您要断开连接@Barguast:为什么您认为不能在服务器端使用
Shutdown()
,然后等待Read()
接收0字节的读取?@Barguast,因为您也在关闭receive
频道。使用SocketShutdown.Send
可以接收“断开连接确认”。“我需要告诉这些循环(及其挂起的ReadAsync-s)停止”--如果您的客户端表现良好,那么当您调用Shutdown(SocketShutdown.Send)
时,它们将在其一端看到0字节的接收,一旦它们完成发送任何内容,他们将调用Shutdown(SocketShutdown.Both)
(或其平台的等效程序),然后您的服务器将看到0字节的接收完成。如果您觉得客户端没有及时响应(即行为不好),您可以选择启动计时器,然后关闭套接字。但这不是正常的情况,即使必须如此supported@Barguast我发现很难确定您仍然觉得缺少哪些信息。行为良好的场景重复了几次,我们还讨论了客户行为不好的可能性。由您决定关闭连接或给每个客户端一些时间来正确关闭连接。@Barguast AfterSocket.Shutdown(Send)
0字节数据包被发送到远程方,当远程方正确响应时,您将读取0-因此这肯定不是立即的。使用Socket.Close()关闭连接时,如果上次传入的消息是在关闭连接时发送的,则可能会错过该消息。
public void Stop()
{
this.tcp.Client.Shutdown(SocketShutdown.Both);
}