【问题标题】:How to use TCP keep_alive property to get notified on the event of a unresponsive peer?如何使用 TCP keep_alive 属性来获得有关无响应对等点事件的通知?
【发布时间】:2020-02-29 13:24:39
【问题描述】:

场景:
我有一个使用boost::asio 1.63 编写的客户端和服务器。一般来说,连接和通信部分工作得很好。

我在双方都编写了一个看门狗,它以 2 秒的间隔向对等方发送虚拟数据包。看门狗的目标是,如果相关对等方在接下来的 2 秒内没有收到它所期望的虚拟数据包,则它会报告连接错误。这对我来说甚至更重要,因为这可能会发生 2 个对等点没有出于任何用户目的处理数据包,但是如果任何对等点出现故障,他们每个人都需要报告连接错误。即使由于内核崩溃,对等方也可能出现故障,在这种情况下,该对等方将无法发送消息。这当然是一个经典的问题,甚至超越了 asio 和 TCP。

我的看门狗运行良好。完全没有问题。

但是,最近我读到了套接字中的keep_alive 功能。我尝试了以下代码,似乎可以通过使用 boost::asio 从我的代码中获取套接字的本机句柄来在 TCP 套接字上调用一个名为 keep_alive 的属性。

boost::asio::io_service      ioService;
boost::asio::ip::tcp::socket mySocket(ioService);

int on = 1;
int delay = 120;
setsockopt(mySocket.native_handle(), SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on));
setsockopt(mySocket.native_handle(), IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay));

问题:
上面的代码在 macOS、Linux 和 iOS 上编译良好。看起来很棒。但是,我如何从中受益?当对等体出现故障时,这会给我一个回调或事件吗?这能让我从编写上面描述的看门狗中解放出来吗?

我已使用boost::asio::async_connect 连接到对等方。当 perr 在定义的超时间隔后下降时,我可以回调我的 connectionHandler 吗?

设置了keep_alive 选项后,我如何才能知道我的对等方不再响应?

【问题讨论】:

  • 你不需要原始的setsockopt,你可以使用mySocket.set_option
  • Does this give me a callback or event when the peer goes down? 我认为它会失败并在您的读写操作中出现退出代码。
  • It wouldn't send me an event if my peer is sitting idle and not doing any read/write. 正确,但是什么时候会发生这种情况?您通常会总是等待数据读取,不是吗?
  • TCP keepalive (a) 默认关闭 (b) 启用时,默认以两小时间隔运行 (c) 如果下次使用套接字进行 I/O,则会导致连接重置检测到死节点。
  • @AdeleGoldberg 我对你如何让它工作很感兴趣。你能写一个(非常)简短的摘要作为self-answer吗?

标签: sockets tcp boost-asio tcp-keepalive


【解决方案1】:

如果在异步操作挂起时检测到断开连接,则会使用相应的错误代码调用套接字的完成处理程序。

问题在于 TCP keep_alive 选项并不总是检测到断开连接。

一般来说,除了实施应用程序级 ping/heartbeat 之外,没有可靠的方法来检测突然断开连接。

你也可以看到this thread

【讨论】:

  • TCP keep-alive 总是检测到断开连接。问题是默认情况下,它的计时器设置为 2 小时不活动,之后它会发送探测。您可以将计时器配置为低得多的值。
  • @Maxim Egorushkin 据我记得,我尝试过这样做(在 Windows 上),但它仍然没有涵盖所有场景。即使是这样,配置 system-wide 参数听起来也不是最佳解决方案。
  • 超时是 Linux 上的每个套接字选项,不确定 Windows。 More details.
  • 我在 macOS、android 和 ios 上尝试了 tcp keep_alive。它似乎为我检测到所有断开连接。我已经非常严格地测试了它。我认为它对我有用。
  • 我不在 Windows 上进行测试。但我已经在 linux 端测试了 killall -9 MyApppkill MyApp 这样的场景。这对于 keep_alive 检测破损也很有效。
猜你喜欢
  • 2021-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-01
  • 1970-01-01
  • 2015-03-20
  • 2018-02-23
  • 1970-01-01
相关资源
最近更新 更多