linux检测socket网络掉线keep-alive

在写TCP/IPServer程时候,发现有时候网线拔了,没有办法检测网络异常,最后在网上找到,用Keep-Alive感觉还不错。
客户端程序异常,在服务端处理这个异常就可以了。网络链路异常如:网线拔出、交换机掉电、客户端机器掉电。当出现这些情况的时候服务端不会出现任何异常。这样的话上面的代码就不能处理这种情况了。如果您需要确定连接的当前状态,请进行非阻止、零字节的 Send 调用。如果该调用成功返回或引发 WAEWOULDBLOCK 错误代码 (10035),则该套接字仍然处于连接状态;否则,该套接字不再处于连接状态。

服务器端和客户端的Socket都设定了keepalive属性。
服务器端设定了探测次数等参数,客户端、服务器只是打开了keepalive机能
服务器端起了一个监视线程,利用select来检测socket是否被关闭

1,keep alive

   对于tcp连接,如果一直在socket上有数据来往就不会触发keepalive,但是如果30秒一直没有数据往来,则keep alive开始工作:发送探测包,受到响应则认为网络,是好的,结束探测;如果没有相应就每隔1秒发探测包,一共发送3次,3次后仍没有相应,则发送RST包关闭连接,也就是从网络开始到你的socket能够意识到网络异常,最多花33秒。但是如果没有设置keep alive,可能你在你的socket(阻塞性)的上面,接收: recv会一直阻塞不能返回,除非对端主动关闭连接,因为recv不知道socket断了。发送:取决于数据量的大小,只要底层协议栈的buffer能放下你的发送数据,应用程序级别的send就会一直成功返回。 直到buffer满,甚至buffer满了还要阻塞一段时间试图等待buffer空闲。所以你对send的返回值的检查根本检测不到失败。开启了keep alive功能,你直接通过发送接收的函数返回值就可以知道网络是否异常。

keepalive就三个参数:

sk->keepalive_probes = 3; //探测次数

sk->keepalive_time   = 30;//探测的超时

sk->keepalive_intvl = 1; //探测间隔

设置的方法(应用层):

linux检测socket网络掉线keep-alive

2,select和keep alive的关系
       select 是为单个进程使用多个socket而设计的,跟检测连接无关,如果只是检测一个socket的话,没有必要使用select。开了keepalive机能 的话,每次调用recv或send时检查返回值,判断是否出错或为0。如果出错,再检查errno查资料,看哪个或哪几个错误号表示链接断了或不存在就可 以了。谁需要定期检查连接状况,谁就启用keep alive。另一端可以不起,只是被动地对探测包进行响应,这种响应是tcp协议的基本要求,跟keep alive无关。并不需要客户端和服务器端都开启keep alive。

3,TCP连接关闭时,需要连接的两端中的某一方发起关闭动作,如果某一方突然断电,另外一端是无法知道的。tcp的keep_alive就是用以检测异常的一种机制。

 这三个选项分别对应TCP_KEEPIDLE、TCP_KEEPINTL和TCP_KEEPCNT的选项值,通过setsockopt进行设置。每隔60s发起一次keepalive的报文,如果没有回应,30秒后进行重试,最多重试9次即认为连接关闭。

 cat /proc/sys/net/ipv4/tcp_keepalive_time
60
cat /proc/sys/net/ipv4/tcp_keepalive_intvl
30
cat /proc/sys/net/ipv4/tcp_keepalive_probes
9

正常通信时连接的另一端主动调用colse关闭连接,tcp连接已经关闭会被通知。但是如果tcp连接的另一端突然掉线,或者重启断电,这个时候我们并不知道网络已经关闭。而此时,如果有发送数据失败,tcp会自动进行重传。重传包的优先级高于keepalive,那就意味着,我们的keepalive总是不能发送出去。 这时候而此时,我们也并不知道该连接已经出错而中断。在较长时间的重传失败之后,我们才会知道。