3

我在SuSE Linux Enterprise Server 12.3 (x86_64)上用C 语言编写了一个多客户端服务器程序,每个客户端使用一个线程来接收数据。

我的问题是:
我使用一个终端运行服务器,并使用其他几个终端连接telnet到我的服务器(作为客户端)。我recv()在服务器中使用过从客户端接收数据,我还应用了检查返回值recv()ie Error on -1; 康涅狄格州关闭0并正常运行其他。我没有在recv().

如果我只是正常使用Ctrl+]and关闭 telnet 会话(即断开客户端),我的程序可以正常工作close,但是如果我使用强制终止客户端,kill <pid>那么我的服务器将无法检测到连接丢失。

如何解决?

约束:我不想在客户端设置条件,我只想在服务器端解决这个问题。

4

3 回答 3

4

您可以SO_KEEPALIVE在服务器中的套接字上启用。

/* enable keep-alive on the socket */
int one = 1;
setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(one));

默认情况下,启用 keep-alive 时,连接必须空闲 2 小时才能尝试进行 keep-alive 探测。您可以通过调整TCP_KEEPIDLE参数将保持活动时间调整为更具侵略性:

int idletime = 120; /* in seconds */
setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &idletime, sizeof(idletime));

发送探测时,它期望来自另一端的确认。如果有确认,则探测将保持静默,直到空闲计时器再次到期。如果未收到对探测的确认,则默认情况下每 75 秒重试一次保持活动探测。这可以通过TCP_KEEPINTVL选项进行调整。该TCP_KEEPCNT选项控制有多少连续失败触发连接被丢弃。默认情况下,该数字为 9。

这些选项在 Linux 上可用。BSD 有类似的选项,但名称不同。

于 2013-08-19T07:26:06.117 回答
2

如果我只是使用 Ctrl+] 正常关闭 telnet 会话(即断开客户端)并关闭,我的程序工作正常,但如果我使用 kill 或关闭终端强制终止客户端,那么我的服务器无法检测到连接丢失。

在任何一种情况下,客户端套接字在销毁 telnet 进程时都会被 telnet 或内核关闭。您的服务器必须接收FIN导致recv()返回 0 的段(在从套接字读取所有待处理数据之后)。

您可能没有recv()正确处理所有返回代码。

于 2013-08-19T09:54:36.750 回答
2

你所能做的就是实现某种超时。您将无法确定客户端已断开连接,除非它自己实际断开连接。您将得到的最接近的结果是注意到客户被要求发送一些东西并且未能及时发送。

至于为什么:TCP只是IP之上的一层。实际上没有连接两台计算机。“连接”只是确认另一台机器存在并同意使用 TCP 与您交换信息。“连接”抽象只有在双方都按照规则行事时才成立。强行终止客户端使其无法阻止交易结束,因此服务器处于挂起状态。

于 2013-08-19T07:10:17.137 回答