【发布时间】:2012-09-25 02:24:03
【问题描述】:
嘿,伙计。我刚刚使用 sys/socket 用 C++ 编写了一个客户端和服务器。我需要处理客户端仍处于活动状态但服务器已关闭的情况。一种建议的方法是使用心跳来定期断言连接性。如果没有尝试在 Y 时间段内每 X 秒重新连接一次,然后超时。
这种“心跳”是检查连接的最佳方式吗?
我正在使用的套接字可能有关于它的信息,有没有办法检查是否存在连接而不会弄乱缓冲区?
【问题讨论】:
嘿,伙计。我刚刚使用 sys/socket 用 C++ 编写了一个客户端和服务器。我需要处理客户端仍处于活动状态但服务器已关闭的情况。一种建议的方法是使用心跳来定期断言连接性。如果没有尝试在 Y 时间段内每 X 秒重新连接一次,然后超时。
这种“心跳”是检查连接的最佳方式吗?
我正在使用的套接字可能有关于它的信息,有没有办法检查是否存在连接而不会弄乱缓冲区?
【问题讨论】:
如果您在 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 之上)支持某种“无所事事”请求或数据包 - 每一方都可以使用它来跟踪他们最后一次从另一方收到东西的时间,然后可以如果数据包之间的时间过长,请关闭连接。
请注意,这是假设您使用的是 TCP/IP。如果您使用的是 UDP,那就是另一回事了,因为它是无连接的。
【讨论】:
好的,我不知道你的程序做了什么或什么,所以也许这不可行,但我建议你避免尝试始终保持套接字打开。它应该只在您使用时打开,在您不使用时应关闭。
如果您在等待用户输入的读取和写入之间,请关闭套接字。设计您的客户端/服务器协议(假设您是手动执行此操作,而不使用任何标准协议,如 http 和/或 SOAP)来处理此问题。
如果连接断开,套接字将出错;编写程序,以便在写入套接字期间发生此类错误时不会丢失任何信息,并且在从套接字读取期间发生错误时不会获得任何信息。事务性和原子性应该被纳入您的客户端/服务器协议(同样,假设您自己设计它)。
【讨论】:
也许这会对你有所帮助,TCP Keepalive HOWTO 或者这个SO_SOCKET
【讨论】: