如何使用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()所有返回代码。