2

我有一个 C++ 网络应用程序,它接受来自客户端的 TCP 连接,然后在套接字上等待,直到客户端决定发送数据(有时他们不会在很长一段时间内发送任何东西,这没关系)。

它主要在客户端崩溃或机器关闭时检测错误情况,但是当连接到客户端的网络电缆被拔下时,它需要很长时间才能注意到,我希望它尽快注意到这种情况。

我无法控制客户,也不能让他们发送类似“ping”的东西。我的服务器确实向客户端发送了一个“ping”数据包(但它们不会发送响应),但即使拔下电缆,write() 也会返回正确的字节数(我看到 TCP 堆栈发送重试Wireshark 中的数据包)。

发现连接丢失的最佳方法是什么?如果我可以在 write() 调用中检测到它,那将是最方便的。

我需要它才能在 Windows 和 Linux 上工作。

4

3 回答 3

3

抱歉,如果没有 ping/keepalives,就无法及时检测到异常断开连接。甚至操作系统也不总是知道电缆已被拉动。这就是为什么write()仍然有效 - 套接字很高兴地在其输出缓冲区中缓冲数据,等待稍后发送它,因为套接字状态尚未被操作系统无效。最终,socket会在内部超时,此时OS终于可以使连接失效,让socket在后续操作中报错。但这可能需要很长时间,正如您所注意到的。

由于您无法发送应用层 ping,请至少尝试启用套接字层 keep-alives。这可能会有所帮助。仅在 Windows 2000+ 上,您可以使用SIO_KEEPALIVE_VALSsocket 选项 via WSAIoctl(),它可以让您设置 keep-alives 的实际计时器值。在所有平台上,您都可以使用SO_KEEPALIVE选项 via setsockopt(),但这不允许您配置计时器值,因此使用默认值。

于 2013-01-09T01:45:05.827 回答
3

不幸的是,没有办法区分在另一端被拉出的电缆与任何其他丢包原因。话虽如此,您可以将另一端的连接丢失近似为在足够长的时间段(例如 T)内发生的“无限丢包”。TCP 跟踪数据包丢失,因此执行此操作的一般方法是:

  • 获取连接中未确认的字节数(假设为 B)
  • 发送数据,大小 = N
  • 设置 timeout = T,当它触发时,再次检查未确认的字节数。如果是B+N,则假设对方已经失去连接。此时,您可以尝试 ICMP echo 来验证您的假设。

获取连接的 TCP 特定信息不是 UNIX 上的标准接口,也绝对不能移植到 Windows。在 Linux 上,有一个名为 TCP_INFO 的套接字选项,您可以通过 getsockopt() 调用它。谷歌应该给你一些例子。我不知道 Windows 上是否有等效选项。

另一种方法(即近似跟踪连接丢失)是通过 RAW 套接字。打开一个 RAW 套接字并对其进行过滤以仅接收用于您的连接的 TCP 流量。然后,与其从 TCP 获取信息以确定您是否从另一端获得任何信息,不如等待从另一端接收任何数据包。如果在规定的时间内得到了东西,那么就说明对端还在。

于 2013-01-09T02:16:36.660 回答
1

你的问题很复杂。您和您的客户之间有很多事情可能会出错。不仅仅是“拔出”的电缆。

如果您只是想知道您的用户是否仍然在线,您可以建立一个新的 TCP 连接。因为您需要完成 3 次握手才能成功建立 TCP 连接,所以您知道连接成功初始化时客户端在线。这样做的问题是,如果您想保持当前连接处于活动状态,则需要另一个端口。不知道这是否是您的问题。

但是从它的声音来看,您并没有真正从您的客户端发送和接收数据(除了一些 ping 数据)。因此,您可以简单地将您的应用程序设置在一个循环中以每隔 X 秒设置一个 TCP 连接(前两个步骤 - 因此接收 ACK - 应该足以确定您的客户端是否仍在处理网络数据)。如果您在 X 毫秒内没有得到响应,您可以非常可靠地说您的客户端或介于两者之间的东西停止了“工作”。

希望这可以帮助。如果没有,请提供有关您的工具在做什么的更多信息。

于 2013-01-09T01:48:04.760 回答