Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/visual-studio/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 网络流异常和返回代码_C#_Async Await_Tcpclient_Networkstream - Fatal编程技术网

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)
    通知远程方您要断开连接

  • 您的循环仍可能接收远程方发送的数据

  • 如果一切正常,您的循环将收到一个0字节的数据包,表明远程方正在断开连接

  • 循环以正确的方式终止

  • 如果尚未收到0字节数据包,则可能需要在一定时间后决定处置套接字


  • @Barguast:为什么您认为不能在服务器端使用
    Shutdown()
    ,然后等待
    Read()
    接收0字节的读取?@Barguast,因为您也在关闭
    receive
    频道。使用
    SocketShutdown.Send
    可以接收“断开连接确认”。“我需要告诉这些循环(及其挂起的ReadAsync-s)停止”--如果您的客户端表现良好,那么当您调用
    Shutdown(SocketShutdown.Send)
    时,它们将在其一端看到0字节的接收,一旦它们完成发送任何内容,他们将调用
    Shutdown(SocketShutdown.Both)
    (或其平台的等效程序),然后您的服务器将看到0字节的接收完成。如果您觉得客户端没有及时响应(即行为不好),您可以选择启动计时器,然后关闭套接字。但这不是正常的情况,即使必须如此supported@Barguast我发现很难确定您仍然觉得缺少哪些信息。行为良好的场景重复了几次,我们还讨论了客户行为不好的可能性。由您决定关闭连接或给每个客户端一些时间来正确关闭连接。@Barguast After
    Socket.Shutdown(Send)
    0字节数据包被发送到远程方,当远程方正确响应时,您将读取0-因此这肯定不是立即的。使用Socket.Close()关闭连接时,如果上次传入的消息是在关闭连接时发送的,则可能会错过该消息。
        public void Stop()
        {
            this.tcp.Client.Shutdown(SocketShutdown.Both);
        }