Linux的插座:如何检测断开的网络中的客户端程序?(Linux Socket: How to de

2019-07-19 15:37发布

我调试基于Linux的交流插座程序。 由于在网站上提供的所有例子中,我采用以下结构:

sockfd= socket(AF_INET, SOCK_STREAM, 0);

connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));

send_bytes = send(sockfd, sock_buff, (size_t)buff_bytes, MSG_DONTWAIT);

当删除服务器关闭其服务器程序,我可以检测到断线。 但是,如果我拔掉网络线,发送功能仍然会返回正值,而不是-1。

如何检查在客户端程序假设我不能改变服务器端的网络连接?

Answer 1:

但是,如果我拔掉网络线,发送功能仍然会返回正值,而不是-1。

首先你应该知道send实际上不发送任何东西,它只是一个内存复印功能/系统调用。 它从过程到内核拷贝数据 - 晚些时候内核将获取数据并在段和包包装之后发送给对方。 因此send只能返回如果有错误:

  • 套接字是无效的(例如假的文件描述符)
  • 连接显然是无效的,例如,它尚未建立或者已经以某种方式被终止(FIN,RST,超时 - 见下文)
  • 有没有更多的空间来复制数据

主要的一点是, send不发送任何东西,因此它的返回码不告诉你实际数据到达对方的任何事情

回到你的问题,当TCP发送数据,预计在合理时间内的有效确认。 如果没有得到一个,它重新发送。 多久它重新发送? 每个TCP协议栈做不同的事情,但规范是使用指数退避。 也就是说,第一等待1秒,然后如图2所示,然后4等。 在一些堆叠这个过程可能需要几分钟。

主要的一点是,在中断的情况下,TCP将只有认真大型沉寂一段时间后死亡宣告的连接(在Linux上它确实像15重-超过5分钟)。

解决方法之一是实现在应用程序中的一些确认机制。 例如,您可以“ 在5秒钟内答复,否则我就声明这一点上死了 ”向服务器发送一个请求,然后recv一个超时。



Answer 2:

为了检测遥控器断开,做一个read()

检查此线程的详细信息:

可以阅读连接socket()函数返回零个字节?



Answer 3:

你不仅可以与调用write()funcation检测拔出以太网电缆。 这是因为通过TCP协议栈没有你的意识行动的TCP重传。 这里有解决方案。

即使你已经设置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超时ocurrs,可满足您不同的返回事件取决于您使用的平台,所以你不能只有返回事件决定死连接状态。 例如,HP返回POLLERR事件和keepalive超时发生AIX只返回POLLIN事件。 你会满足的recv ETIMEDOUT错误(),在这个时间打电话。

在最近的内核版本(2.6.37以来),你可以使用TCP_USER_TIMEOUT选项将工作做好。 此选项可用于单插座。

最后,您可以使用阅读与MSG_PEEK标志,它可以让你检查插座是好的功能。 (MSG_PEEK只是偷窥数据是否到达内核堆栈缓冲区永不拷贝数据到用户缓冲区。)所以你可以使用这个标志只是为了检查插座是好的,没有任何副作用。



Answer 4:

检查返回值,看它是否等于该值:

EPIPE
此套接字连接,但现在连接被中断。 在这种情况下,发送第一生成SIGPIPE信号; 如果信号被忽略或阻塞,或者如果处理程序返回,然后发送失败,EPIPE。

还添加了支票处理函数中的SIGPIPE信号,使其更加可控。



文章来源: Linux Socket: How to detect disconnected network in a client program?