首页 > 解决方案 > TCP 套接字可能会中断以使其仍在接收但不能再发送?

问题描述

使用套接字编程 15 年,以前从未遇到过这种情况。

运行一个标准的 TCP 套接字服务器,客户端连接到它,并通过打开的套接字来回发送消息。这是一个游戏服务器,客户端在服务器运行的游戏世界中运行。该服务器在过去 3 个月中处理了 160 万个此类套接字会话。

服务器正在记录从客户端接收到的消息。客户端正在记录从服务器接收到的消息,并记录它发送到服务器的消息。

我刚刚从一位最终用户那里收到了一份错误报告,他们在会话的中途似乎出现了连接丢失的问题,并且查看日志,看起来连接仅在一个方向上断开了。客户端的发送没有通过,即使服务器的发送一直很好。

在许多消息来回传递了很多分钟之后,服务器从该客户端接收到最后一条消息,然后通过该套接字不再接收任何内容。另一方面,客户端一直在不断地从服务器接收消息,并且一直在向服务器发送消息(从它的角度来看——这些是小消息,可能只是在发送中堆积缓冲)。

服务器最终检测到客户端处于空闲状态,发送了一条再见消息,并关闭了连接。客户甚至收到了告别信息。

这个过程持续了 18 秒(从服务器收到来自客户端的最后一条消息到发送再见消息的时间)。

问题:对于 TCP 套接字,这种行为是否可能?它仅在一个方向中断或停止?

我正在考虑应该通过的确认。如果客户端->服务器路由被破坏,那么服务器将不再收到确认。这意味着服务器将在超时后一遍又一遍地重新发送所有数据包。但这并不意味着它将停止发送新数据包。客户端也不会收到它正在发送的数据包的任何确认,但出于不同的原因(数据包根本没有通过,因此服务器无法确认它们),所以它也会超时并重新发送。

也许这不是一个 TCP 问题,而是一个网络路由问题。2路路线只能以一种方式中断吗?

标签: socketsnetworkingtcprouting

解决方案


我认为这可能是一个路由问题。上面关于单向流量的其他评论仅适用于shutdown(2)您可能知道的情况,因为您的应用程序必须明确地执行此操作。

两个方向的路由可能不同(如@RonMaupin 所述)。或者可能是某个中间路由器在一个方向上存在大量拥塞。任何一种情况都可能导致丢包。

面对这样的丢包,由于没有收到ACK(我认为您已经正确描述),双方将继续重试传输。初始重传时间基于每个端点机器计算的近似往返时间。然后有一个用于后续重传的指数退避——参见例如http://www.pcvr.nl/tcpip/tcp_time.htm#21_2的解释。结果是最终超时。

考虑到指数退避和一定数量的重传(该数量是特定于平台的,通常是可配置的),通常需要超过 18 秒的时间,您的本地网络堆栈才会宣布会话死亡。但听起来您的应用程序可能用自己的超时使这个过程短路(这对于游戏服务器来说似乎是合理的)。

我怀疑您以前从未见过这种情况,因为通常路由在两个方向上都是相同的,并且当路由器“关闭”时,它在两个方向上都处于关闭状态。


推荐阅读