我正在使用循环从c Berkeley套接字读出消息,但我无法检测套接字何时断开连接,因此我接受新的连接。请帮忙
while(true) {
bzero(buffer,256);
n = read(newsockfd,buffer,255);
printf("%s\n",buffer);
}
答案 0 :(得分:16)
检测套接字连接的唯一方法是写入。
在read()/recv()
上获取错误将表明连接已断开,但在读取时未收到错误并不表示连接已启动。
您可能有兴趣阅读此内容: http://lkml.indiana.edu/hypermail/linux/kernel/0106.1/1154.html
此外,使用TCP Keep Alive可以帮助区分不活动和断开的连接(通过定期发送内容,即使应用程序没有数据要发送)。
(编辑:删除了@Damon指出的错误句子,谢谢。)
答案 1 :(得分:0)
您的问题是您完全忽略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()
电话无意义,只是先前错误的解决方法。
答案 2 :(得分:-1)
那是因为你没有使用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)设置较低的值,但这并不像我已经说过的那样精确。 此外,目前您无法仅为单个套接字设置这些值。那些是全局内核参数。 有一些尝试为单个套接字(http://patchwork.ozlabs.org/patch/55236/)应用tcp重新传输套接字选项,但我不认为它已应用于内核主线。我在系统头文件中找不到这些选项定义。
作为参考,您可以通过'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选项将运行良好。此选项可用于单个插槽。