如何使用recv()检测客户端是否仍然连接(而不是挂起)?
我在SuSE Linux Enterprise Server 12.3(x86_64)上用C编写了一个多客户端服务器程序,我每个客户端使用一个线程来接收数据。
我的问题是:
我使用一个终端来运行服务器,并使用其他几个终端telnet
到我的服务器(作为客户端)。 我已经在服务器中使用recv()
来从客户端接收数据,我还应用了recv()
返回值的检查,即错误在-1
; Conn。在0
和正常操作时关闭。 我没有在recv()
使用任何标志。
如果我通常使用Ctrl+]
关闭telnet会话(即断开客户端)并close
,我的程序工作正常,但如果我使用kill
强制终止客户端,那么我的服务器无法检测到连接丢失。
如何解决?
约束:我不想在客户端放置条件,我只想在服务器端解决此问题。
您可以在服务器的套接字上启用SO_KEEPALIVE
。
/* enable keep-alive on the socket */ int one = 1; setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(one));
默认情况下,启用keep-alive时,连接必须在尝试保持活动探测之前空闲2小时。 您可以通过调整TCP_KEEPIDLE
参数来调整保持活动时间以使其更具攻击性:
int idletime = 120; /* in seconds */ setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &idletime, sizeof(idletime));
发送探测时,它需要来自另一端的确认。 如果有确认,则探测保持静默,直到空闲计时器再次到期。 如果未收到对探测的确认,则默认情况下每75秒再次重试保持活动探测。 这可以使用TCP_KEEPINTVL
选项进行调整。 TCP_KEEPCNT
选项控制触发连接丢失的连续故障数。 默认情况下,该数字为9。
这些选项在Linux上可用。 BSD有类似的选项,但命名不同。
关于你所能做的就是实现某种超时。 您将无法确定客户端已断开连接,除非它实际上已断开连接。 您最接近的是注意到客户端需要发送一些内容并且未能及时发送。
至于原因:TCP只是IP之上的一层。 实际上并没有连接两台计算机; “连接”只是确认另一台机器存在并同意使用TCP与您交换信息。 只要双方按照规则行事,“连接”抽象就会成立。 强行查杀客户端使其无法阻止其交易结束,因此服务器处于闲置状态。
如果我通常使用Ctrl +]关闭telnet会话(即断开客户端)并关闭,我的程序工作正常,但如果我使用kill或关闭终端强制终止客户端,那么我的服务器无法检测到连接丢失。
在任何一种情况下,客户端套接字在telnet进程销毁时都会被telnet或内核关闭。 您的服务器必须接收FIN
段,这会导致recv()
返回0(在从套接字读取所有挂起数据之后)。
您可能无法正确处理recv()
所有返回代码。