我在 SuSE Linux Enterprise Server 12.3(x86_64)上的 C 中编写了一个多客户端服务器程序,我在每个客户端使用一个线程来接收数据。
我的问题是:
我正在使用一个终端来运行服务器,并使用其他几个终端到telnet
到我的服务器(作为客户端)。我在服务器中使用recv()
来接收来自客户端的数据,我还应用recv()
的返回值检查,即-1
上的错误; Conn。在0
&正常运作。我没有使用recv()
中的任何标志。
如果我通常使用Ctrl+]
和close
关闭telnet会话(即断开连接客户端),我的程序运行正常,但如果我使用kill <pid>
强制终止客户端,那么我的服务器是无法检测到连接丢失。
如何解决这个问题?
约束:我不想在客户端放置条件,我只想在服务器端解决这个问题。
答案 0 :(得分:4)
您可以在服务器的套接字上启用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有类似的选项,但名称不同。
答案 1 :(得分:2)
关于你所能做的就是实现某种超时。您将无法确定客户端已断开连接,除非它实际上已断开连接。你得到的最接近的是注意到客户需要发送一些东西并且未能及时这样做。
至于原因:TCP只是IP之上的一层。实际上并没有连接两台计算机; “连接”只是确认另一台机器存在并同意使用TCP与您交换信息。只要双方按照规则行事,“连接”抽象就会成立。强行杀死客户端使其无法阻止交易结束,因此服务器处于闲置状态。
答案 2 :(得分:2)
如果我只是正常使用Ctrl +]关闭telnet会话(即断开客户端)并关闭,我的程序运行正常,但如果我使用kill或关闭终端强行终止客户端,那么我的服务器无法检测到连接丢失
在任何一种情况下,客户端套接字在telnet进程销毁时都会被telnet或内核关闭。您的服务器必须收到FIN
段,导致recv()
返回0(从套接字读取所有待处理数据后)。
您可能无法正确处理recv()
的所有退货代码。