Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/294.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# 异步tcp套接字的奇怪行为_C#_Sockets_Asyncsocket - Fatal编程技术网

C# 异步tcp套接字的奇怪行为

C# 异步tcp套接字的奇怪行为,c#,sockets,asyncsocket,C#,Sockets,Asyncsocket,我有一个异步服务器套接字监听某个端口。然后从另一台pc连接到服务器并发送1个字节。一切正常,但有一个奇怪的行为。当我拔出网络电缆并尝试发送1个字节时(在操作系统意识到电缆被拔出之前),我没有得到任何异常/错误,正如预期的那样,服务器没有收到该数据包。插座就是这样工作的吗?这是否意味着在连接丢失的情况下,某些数据包可能会丢失(因为我没有收到异常,也不知道请求没有发送)? 代码如下: private void button3_Click(object sender, EventArgs e)

我有一个异步服务器套接字监听某个端口。然后从另一台pc连接到服务器并发送1个字节。一切正常,但有一个奇怪的行为。当我拔出网络电缆并尝试发送1个字节时(在操作系统意识到电缆被拔出之前),我没有得到任何异常/错误,正如预期的那样,服务器没有收到该数据包。插座就是这样工作的吗?这是否意味着在连接丢失的情况下,某些数据包可能会丢失(因为我没有收到异常,也不知道请求没有发送)? 代码如下:

    private void button3_Click(object sender, EventArgs e)
    {
        var b = new byte[1] {1};
        client.BeginSend(b, 0, b.Length, 0, new AsyncCallback(SendCallback), client);
    }

    private void SendCallback(IAsyncResult ar)
    {
        Socket client = (Socket)ar.AsyncState;

        int bytesSent = client.EndSend(ar);

        this.Invoke(new MethodInvoker(() => { MessageBox.Show(bytesSent.ToString() + " bytes sent"); }));
    }

发送者怎么可能知道包裹没有收到?它把它送入一个黑洞,等待答复。只要没有回复,他就无法知道该数据包是否已收到或永远不会收到

这通常通过超时来解决。最终,TCP堆栈将声明连接已断开,或者随后的读取超时

发送根本不能保证交货

让对方给你一份确认书。您的确认书最终将超时


或者,
关闭(发送)
套接字。这确保了交付,并将引发异常(超时后)。您应该在关闭套接字之前关闭(两者)套接字,以确保收到所有错误的通知。

我假设您创建了一个TCP套接字

在这种情况下,断开连接时不会通知您的客户端(除非您的应用程序发送了某种注销消息)

查看连接的
属性

Connected属性获取客户端套接字的连接状态 从上次I/O操作开始。当它返回false时,客户端套接字 从未连接或不再连接


“截至最后一次I/O”操作:只有从客户端读取(不成功)数据才能帮助您检测断开连接。许多应用程序实现“ping”来检测某些断开连接。

是的,这就是TCP套接字的工作方式。不,这并不意味着数据包必然丢失

在封面下发生的事情是这样的。调用BeginSend时,发送的字节将传递给操作系统的TCP堆栈。然后,TCP堆栈以数据包的形式发送数据

当数据包在合理的时间长度内未被确认时,TCP堆栈会自动重新发送数据包。只要没有收到确认数据包,这种情况就会重复发生

如果您重新插入电缆,其中一个重发将通过,服务器将延迟看到数据。这是理想的行为。记住,TCP是在冷战期间设计用来传输军事数据的;当时的想法是,即使网络的一部分遭到破坏,路由系统最终也会调整以找到另一条通向接收者的路径,数据最终也会通过

如果不重新插入电缆,大多数TCP堆栈最终将放弃,从而终止连接。然而,这需要几分钟的时间

有关TCP重传超时的更多信息,请参见RFC 1122:


套接字层的Windows在内核中维护一个套接字缓冲区。在应用层成功发送意味着数据被复制到内核缓冲区。此缓冲区中的数据由TCP堆栈推送到远程应用程序。在windows中,如果数据包被丢弃,TCP将重新发送数据3次,然后TCP堆栈通知靠近应用程序的连接。重试间隔由RTT决定。第一次重试在1*RTT之后,第二次重试在2*RTT之后,第三次重试在3*RTT之后。在您的例子中,您发送的1字节只是复制到内核缓冲区中&表示成功。需要3*RTT才能指示插座已关闭。只有在调用任何套接字API或监视套接字的关闭事件时,才会通知此连接关闭。拔出电缆后,如果您在3*RTT之后排队等待第二次发送,则发送应通过异常。另一种立即获取发送失败指示的方法是将发送套接字缓冲区大小设置为零(SetSocketOption(..,SendBuffer,..),以便TCP堆栈直接使用您的缓冲区并立即指示失败。

您是否收到回叫?如果您重新插入网络电缆,它最终会传输数据吗?你等了多久了?是的,呼叫了SendCallback。在我将电缆插入您的回调中时,
bytesSent
的值是多少?您已经说过了,但我想澄清一点:只有在某些情况下,Connected属性才可靠地为false。即使网络瘫痪,仅仅发送一些东西也不一定会使其成为错误。它几乎一文不值。这是一种启发。对于可靠的错误发现,您需要一些其他的东西。是的,对于可靠的东西,每N秒发送一次ping。我听说TCP保证传递。。。这就是为什么我感到困惑,但在我的情况下它不会重新发送。重新连接电缆后,数据包未送达。