【问题标题】:What is the best way to implement a heartbeat in C++ to check for socket connectivity?在 C++ 中实现心跳以检查套接字连接的最佳方法是什么?
【发布时间】:2012-09-25 02:24:03
【问题描述】:

嘿,伙计。我刚刚使用 sys/socket 用 C++ 编写了一个客户端和服务器。我需要处理客户端仍处于活动状态但服务器已关闭的情况。一种建议的方法是使用心跳来定期断言连接性。如果没有尝试在 Y 时间段内每 X 秒重新连接一次,然后超时。

这种“心跳”是检查连接的最佳方式吗?

我正在使用的套接字可能有关于它的信息,有没有办法检查是否存在连接而不会弄乱缓冲区?

【问题讨论】:

    标签: c++ sockets heartbeat


    【解决方案1】:

    如果您在 IP 网络上使用 TCP 套接字,则可以使用 TCP 协议的 keepalive 功能,该功能将定期检查套接字以确保另一端仍然存在。 (这还有一个好处,就是让您的套接字的转发记录在您的客户端和服务器之间的任何 NAT 路由器中保持有效。)

    这里有一个TCP keepalive overview,它概述了您可能想要使用 TCP keepalive 的一些原因; this Linux-specific HOWTO 描述了如何配置您的套接字以在运行时使用 TCP keepalive。

    看来您可以通过使用WSAIoctl() 函数设置SIO_KEEPALIVE_VALS 在Windows 套接字中启用TCP keepalive。

    如果您在 IP 上使用 UDP 套接字,则需要在协议中构建自己的心跳。

    【讨论】:

    • 这是一个非常糟糕的解决方案。 TCP keepalive 非常不灵活,无法为您提供控制它们发送频率的好方法。如果您可以像 OP 那样控制双方,那么最好将连接活性测试设计到您自己的协议中。
    • 嘿,链接出了点问题 - tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html 似乎坏了
    • @DavidSchwartz 只是为了详细说明您对 TCP keepalives 的建议,因为这很少被讨论(因此从未使用过它的人的建议):实际上有可以更改的参数,例如“ keepalive time”、“keepalive interval”、“keepalive probes”,但这些设置适用于整个系统,而不是每个套接字,即它们不适用于同一系统上的多个用例。另外,在大多数情况下,默认设置很糟糕,比如 2 小时的保活时间。并且不可能以与操作系统无关的方式更改它们。
    【解决方案2】:

    是的,这种心跳是最好的方式。您必须将其构建到服务器和客户端用于通信的协议中。

    最简单的解决方案是让客户端定期发送数据,如果服务器在特定时间段内没有收到来自客户端的任何数据,则服务器关闭连接。这非常适用于客户端发送查询和服务器发送响应的查询/响应协议。

    例如,您可以使用以下方案:

    1. 服务器响应每个查询。如果服务器在两分钟内没有收到查询,则会关闭连接。

    2. 客户端发送查询并在每次查询后保持连接打开。

    3. 如果客户端一分钟未发送查询,它会发送“你在吗”查询。服务器响应“是的,我是”。这会重置服务器的两分钟计时器并向客户端确认连接仍然可用。

    如果过去一分钟不需要发送查询,让客户端关闭连接可能更简单。由于所有操作都是由客户端发起的,所以如果它需要执行新的操作,它总是可以打开一个新的连接。这将其简化为:

    1. 如果服务器在两分钟内没有收到查询,则关闭连接。

    2. 如果客户端在一分钟内不需要发送查询,则关闭连接。

    但是,这并不能确保客户端始终存在服务器并准备好接受查询。如果您需要此功能,则必须在您的协议中实现“你在吗”“是的我在”查询/响应。

    【讨论】:

    • 如果是我提问,我会将您的帖子标记为答案。
    【解决方案3】:

    如果对方已经离开(即进程已经死亡,机器已经宕机等),尝试从套接字接收数据应该会导致错误。但是,如果另一侧只是挂起,则插座将保持打开状态。在这种情况下,心跳很有用。确保您使用的任何协议(在 TCP 之上)支持某种“无所事事”请求或数据包 - 每一方都可以使用它来跟踪他们最后一次从另一方收到东西的时间,然后可以如果数据包之间的时间过长,请关闭连接。

    请注意,这是假设您使用的是 TCP/IP。如果您使用的是 UDP,那就是另一回事了,因为它是无连接的。

    【讨论】:

      【解决方案4】:

      好的,我不知道你的程序做了什么或什么,所以也许这不可行,但我建议你避免尝试始终保持套接字打开。它应该只在您使用时打开,在您不使用时应关闭。

      如果您在等待用户输入的读取和写入之间,请关闭套接字。设计您的客户端/服务器协议(假设您是手动执行此操作,而不使用任何标准协议,如 http 和/或 SOAP)来处理此问题。

      如果连接断开,套接字将出错;编写程序,以便在写入套接字期间发生此类错误时不会丢失任何信息,并且在从套接字读取期间发生错误时不会获得任何信息。事务性和原子性应该被纳入您的客户端/服务器协议(同样,假设您自己设计它)。

      【讨论】:

      • 一直关闭和重新打开套接字有什么好处?
      • 您不依赖或浪费外部资源。同样,我不知道程序做了什么,但大多数程序花费更多的时间等待用户输入,而不是写入或读取网络。在那些时候不需要打开套接字。
      • 嗯。您正在添加额外的代码和额外的工作来为自己节省一个套接字。 Web 浏览器使用 以这种方式工作,但它太慢了,无法继续删除和重新创建连接。这就是为什么在 HTTP/1.1 中添加了 keepalive。
      • 现代浏览器是否在用户请求之间保持套接字打开?不,不是的。添加 Keepalive 是因为在一个网页中涉及的所有内容实际上构成了一个请求,因此最好继续使用同一个套接字。
      • 另外,我认为我们不同意“额外代码和额外工作”的含义。我个人认为,一个程序会尝试始终保持套接字打开,无论什么深入到“额外代码和额外工作”的领域。
      【解决方案5】:

      也许这会对你有所帮助,TCP Keepalive HOWTO 或者这个SO_SOCKET

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-09-15
        • 2014-03-29
        • 2020-04-19
        • 2013-08-10
        • 1970-01-01
        • 2011-01-03
        相关资源
        最近更新 更多