当 TCP 连接中的链接断开时的 send() 函数行为

Posted

技术标签:

【中文标题】当 TCP 连接中的链接断开时的 send() 函数行为【英文标题】:send() function behavior when link goes down in a TCP connection 【发布时间】:2013-06-23 23:54:50 【问题描述】:

以下是场景:

A B

我在 A 和 B(基于 Linux 的机器)上都使用非阻塞套接字。 A 和 B 有一个 TCP 连接,连接它们的链接突然断开(链接可能不是直接链接)。 现在链接断开后,当在 A 端调用 send() 函数向 B 发送一些数据时,它成功返回(即返回要发送的字节数)。

这种行为的原因是什么,当我们知道远程端将无法接收此数据时,链接已断开?

【问题讨论】:

您确定您使用的是 TCP 吗?另外,链接失效是什么意思?你是关闭B上的插座,还是拔掉它? 我没有关闭套接字。拔掉电源更能描述场景 我认为在这种情况下,场景的语义很重要。如果计算机 B 仍在网络上,并且您向它发送数据包,那么即使数据包没有被发送到应用层,它的网卡也可能正在发回一个 ack。如果它在网络上,这可能是您收到成功返回值的原因。 在我的情况下,实际上 A 和 B 是路由器。我在 A 发出一个端口关闭命令,它应该停止所有从 A 传出的数据包。 所以你从 A 发送到 B,你关闭了 A 并且 A 仍然发送所有的数据包?也许它会等到缓冲区为空才能关闭/它会刷新输出缓冲区。 【参考方案1】:

这是正常的预期行为。

当我们知道远程端将无法接收此数据时

好吧,也许知道,因为你是你拉电缆的那个人,你不打算再次将它重新插入,而是计算机(或者,特别是 TCP 堆栈) 不知道。

它不知道数据不会成功的第一个原因是,当send() 调用完成时,数据还没有传输到网络上:它们只是在一个队列中排队缓冲区。

它不知道数据不会成功的第二个原因是它无法(至少在开始时)分辨出只是丢弃数据包的链接和数据包可能通过的时间之间的区别它试图重新传输它,而不是一根已经完全切断的电缆。即使电缆被切断,TCP 也会继续重传一段时间,希望 (1) 链路恢复正常,或者 (2) 路由器将汇聚到另一条有效的网络路径上。

即使您可以立即知道链接何时断开(尽管在某些非常特殊的情况下您可以,但一般情况下您不能,您必须等待超时才能解决这个问题),您也不希望 TCP每次发生时立即断开连接:如果每次网络中丢失数据包时 TCP 连接都断开,那将太脆弱了。

【讨论】:

数据在 TCP 发送缓冲区中排队后,send() 调用是否返回成功? 假设我没有插上电线,这是否意味着如果没有收到 ack,TCP 会一直重传数据包?它什么时候会真正检测到链路故障? 是的,一旦内核接受了数据,send() 就会返回成功。如果您从不重新插入线路,TCP 最终将超时(通常在几分钟后)并且对套接字的进一步操作将返回超时错误。 TCP 中默认的重传超时时间是多少?它将尝试重新传输丢失数据包的频率 是否有描述此行为的参考资料?

以上是关于当 TCP 连接中的链接断开时的 send() 函数行为的主要内容,如果未能解决你的问题,请参考以下文章

为啥当 XMPP 连接断开时,出席类型用户从不可用变为可用

当用户的数据连接因 tigase 断开时,我如何解决不获取 XMPP 状态更新的问题

当互联网连接或断开时得到通知

java tcp中客户端不能接收到服务器的信息!

Xshell如何设置,当连接断开时保留Session,保留原文字

boost异步tcp通信技术练习