sockets - TCP 套接字可能会中断以使其仍在接收但不能再发送?
问题描述
使用套接字编程 15 年,以前从未遇到过这种情况。
运行一个标准的 TCP 套接字服务器,客户端连接到它,并通过打开的套接字来回发送消息。这是一个游戏服务器,客户端在服务器运行的游戏世界中运行。该服务器在过去 3 个月中处理了 160 万个此类套接字会话。
服务器正在记录从客户端接收到的消息。客户端正在记录从服务器接收到的消息,并记录它发送到服务器的消息。
我刚刚从一位最终用户那里收到了一份错误报告,他们在会话的中途似乎出现了连接丢失的问题,并且查看日志,看起来连接仅在一个方向上断开了。客户端的发送没有通过,即使服务器的发送一直很好。
在许多消息来回传递了很多分钟之后,服务器从该客户端接收到最后一条消息,然后通过该套接字不再接收任何内容。另一方面,客户端一直在不断地从服务器接收消息,并且一直在向服务器发送消息(从它的角度来看——这些是小消息,可能只是在发送中堆积缓冲)。
服务器最终检测到客户端处于空闲状态,发送了一条再见消息,并关闭了连接。客户甚至收到了告别信息。
这个过程持续了 18 秒(从服务器收到来自客户端的最后一条消息到发送再见消息的时间)。
问题:对于 TCP 套接字,这种行为是否可能?它仅在一个方向中断或停止?
我正在考虑应该通过的确认。如果客户端->服务器路由被破坏,那么服务器将不再收到确认。这意味着服务器将在超时后一遍又一遍地重新发送所有数据包。但这并不意味着它将停止发送新数据包。客户端也不会收到它正在发送的数据包的任何确认,但出于不同的原因(数据包根本没有通过,因此服务器无法确认它们),所以它也会超时并重新发送。
也许这不是一个 TCP 问题,而是一个网络路由问题。2路路线只能以一种方式中断吗?
解决方案
我认为这可能是一个路由问题。上面关于单向流量的其他评论仅适用于shutdown(2)
您可能知道的情况,因为您的应用程序必须明确地执行此操作。
两个方向的路由可能不同(如@RonMaupin 所述)。或者可能是某个中间路由器在一个方向上存在大量拥塞。任何一种情况都可能导致丢包。
面对这样的丢包,由于没有收到ACK(我认为您已经正确描述),双方将继续重试传输。初始重传时间基于每个端点机器计算的近似往返时间。然后有一个用于后续重传的指数退避——参见例如http://www.pcvr.nl/tcpip/tcp_time.htm#21_2的解释。结果是最终超时。
考虑到指数退避和一定数量的重传(该数量是特定于平台的,通常是可配置的),通常需要超过 18 秒的时间,您的本地网络堆栈才会宣布会话死亡。但听起来您的应用程序可能用自己的超时使这个过程短路(这对于游戏服务器来说似乎是合理的)。
我怀疑您以前从未见过这种情况,因为通常路由在两个方向上都是相同的,并且当路由器“关闭”时,它在两个方向上都处于关闭状态。
推荐阅读
- matlab - 如何计算图像是否为红色?
- mongodb - 使用嵌套属性的 $group 和 $lookup 在 MongoDB 上加入 2 个文档
- c - 具有不同大小的 C 数组初始化器?
- android - 在 Android 中调用 NotifyDataSetChanged() 时 ArrayAdapter 崩溃
- ruby-on-rails - 安装了 Bundler 2.0.1,Rails 说“必须使用 Bundler 2 或更高版本”?
- sql - Flutter - SQL如何返回纯值
- c# - Blazor 应用程序 Asp.Net Core 2.1 的命名空间中不存在使用 INTEROP 的错误
- linux - 在另一个进程中运行 bash 脚本
- scikit-learn - 如何获得我的 naivebayes-classifier 最重要的特征名称?
- google-cloud-platform - 在 GKE 上运行 Prometheus 时使用 GCP 服务发现