如何检测TCP套接字断开(使用C Berkeley套接字)

我正在使用循环从交流Berkeley套接字读出消息,但我无法检测套接字何时断开连接,所以我接受新的连接。 请帮忙

while(true) { bzero(buffer,256); n = read(newsockfd,buffer,255); printf("%s\n",buffer); } 

检测套接字连接的唯一方法是写入它。

read()/recv()上获取错误将指示连接已断开,但在读取时未收到错误并不意味着连接已启动。

您可能有兴趣阅读本文: http : //lkml.indiana.edu/hypermail/linux/kernel/0106.1/1154.html

此外,使用TCP Keep Alive可以帮助区分非活动连接和断开连接(通过定期发送内容,即使应用程序没有数据要发送)。

(编辑:删除了@Damon指出的不正确的句子,谢谢。)

您的问题是您完全忽略read()返回的结果。 read()之后的代码应该至少看起来像这样:

 if (n == 0) // peer disconnected break; else if (n == -1) // error { perror("read"); break; } else // received 'n' bytes { printf("%.*s", n, buffer); } 

接受新连接应该在一个单独的线程中完成,而不依赖于此连接上的流末尾。

bzero()调用毫无意义,只是先前错误的解决方法。

那是因为你没有使用keepalive超时。 在接收端,keepalive socket选项是检测死连接的最佳解决方案。

但是,如果您的应用程序继续写入套接字,有一些事情要考虑更多。 即使您已经为应用程序套接字设置了keepalive选项,但是如果您的应用程序一直在套接字上写入,您无法及时检测到套接字的死连接状态。 那是因为内核tcp堆栈的tcp重传。 tcp_retries1和tcp_retries2是用于配置tcp重新传输超时的内核参数。 很难预测重传超时的精确时间,因为它是由RTT机制计算的。 你可以在rfc793中看到这个计算。 (3.7。数据通信)

https://www.rfc-editor.org/rfc/rfc793.txt

每个平台都具有用于tcp重传的内核配置。

 Linux : tcp_retries1, tcp_retries2 : (exist in /proc/sys/net/ipv4) 

http://linux.die.net/man/7/tcp

 HPUX : tcp_ip_notify_interval, tcp_ip_abort_interval 

http://www.hpuxtips.es/?q=node/53

 AIX : rto_low, rto_high, rto_length, rto_limit 

http://www-903.ibm.com/kr/event/download/200804_324_swma/socket.pdf

如果你想早期检测到死连接,你应该为tcp_retries2设置较低的值(默认为15),但这并不像我已经说过的那样精确。 此外,目前您无法仅为单个套接字设置这些值。 那些是全局内核参数。 有一些试验为单插槽应用tcp重传套接字选项( http://patchwork.ozlabs.org/patch/55236/ ),但我不认为它已应用于内核主线。 我在系统头文件中找不到这些选项定义。

作为参考,您可以通过’netstat –timers’监控您的keepalive套接字选项,如下所示。 https://stackoverflow.com/questions/34914278

 netstat -c --timer | grep "192.0.0.1:43245 192.0.68.1:49742" tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (1.92/0/0) tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (0.71/0/0) tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (9.46/0/1) tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (8.30/0/1) tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (7.14/0/1) tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (5.98/0/1) tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (4.82/0/1) 

此外,当keepalive超时时,您可以根据您使用的平台遇到不同的返回事件,因此您不能仅通过返回事件来确定死连接状态。 例如,当发生keepalive超时时,HP返回POLLERR事件,AIX仅返回POLLIN事件。 那时你将在recv()调用中遇到ETIMEDOUT错误。

在最近的内核版本(自2.6.37)中,您可以使用TCP_USER_TIMEOUT选项将运行良好。 此选项可用于单个插槽。