java检测tcp存活_keep-alive 和 TCP存活检测

什么是keep-alive?

顾名思义即可,注意它只适用于TCP连接。系统会替你维护一个timer,时间到了,就会向remote peer发送一个probe package,当然里面是没有数据的,对方就会返回一个应答,这时你就知道这个通道保持正常。

有什么用呢?

考虑下面这个场景,端点A和端B开始连接,三次握手,建立好了一个稳定的双向通道。然后双方发送完初始的数据后,进入等待状态。这时候,拔掉B的电源插头,B死掉了,它不可能有任何机会向A发送FIN包,或是其他数据来说明自己挂掉,需要终止连接。因此A只是简单的继续等待。然后重启机器和应用程序,B又恢复原始的状态,可是原本的连接已经没有了,之后就可能有三种情况,双方继续傻等,或是B向A发起新的请求,最可能的还是A向B发送新的数据,这时B因为原有的socket已经死了,就返回一个RST,A关闭连接。看下面的图: _____ _____

| | | |

| A | | B |

|_____| |_____|

^ ^

|--->--->--->-------------- SYN -------------->--->--->---|

|---

|--->--->--->-------------- ACK -------------->--->--->---|

| |

| system crash ---> X

|

| system restart ---> ^

| |

|--->--->--->-------------- PSH -------------->--->--->---|

|---

| |

上面的场景就提出了一个需求,作为服务器端,可不能老是傻等是不是,当然timeout也是一个方案了,不过如果是IM这种类型的服务器,总不能用户一段时间没反应,就把它给踢了吧。

keep-alive还有另外一个有点trick的作用,考虑另外一个场景,一般的终端总是位于防火墙或是NAT后面,而这些设备限制于硬件,不可能处理任意数量的连接,在内部队列满的时候,总是要把最不活跃的连接给砍了的。这个时候keep-alive就可以发挥最用了。看下面的图:

_____ _____ _____

| | | | | |

| A | | NAT | | B |

|_____| |_____| |_____|

^ ^ ^

|--->--->--->---|----------- SYN ------------->--->--->---|

|---

|--->--->--->---|----------- ACK ------------->--->--->---|

| | |

| |

| | |

|--->- PSH ->---|

| | |

程序上如何使用呢?

无论是windows还是linux都实现了这个功能,你只需要设置socket的属性即可,当然你也可自己实现这个功能,也就是定期发送心跳包.

先说linux平台:

一般的实现如下,也就是说每过7200s空闲(两个小时),就会发送一个探测包,如果没有应答,就隔75s,再次发送,连续9次没有反应,就判定该连接死了。

# cat /proc/sys/net/ipv4/tcp_keepalive_time

7200

# cat /proc/sys/net/ipv4/tcp_keepalive_intvl

75

# cat /proc/sys/net/ipv4/tcp_keepalive_probes

9

如何改呢,可以用直接该系统默认值,则全局都会有效,这似乎不大合适。 如果是程序中,则只要设置socket的属性就行了,调用setsockopt,首先打开keep-alive功能:

int optval = 1;

socklen_t optlen = sizeof(optval);

if(setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) < 0) {

perror("setsockopt()");

close(s);

exit(EXIT_FAILURE);

}

然后设定要改的值,像这样:

setsockopt (fd, SOL_TCP, TCP_KEEPIDLE, &newValue, optlen);

TCP_KEEPCNT: 代表 tcp_keepalive_probes

TCP_KEEPIDLE: 代表 tcp_keepalive_time

TCP_KEEPINTVL: 代表 tcp_keepalive_intvl

windows平台上也是差不多:

windows中也是可以做出系统级别的调整的, 对于Win2K/XP/2003,可以从下面的注册表项找到影响整个系统所有连接的参数:

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters]

“KeepAliveTime”=dword:006ddd00

“KeepAliveInterval”=dword:000003e8

“MaxDataRetries”=”5″

在程序中来设定的话,首先先打开keep-alive,跟在linux中是一样的,

BOOL bKeepAlive = TRUE;

int nRet = ::setsockopt(socket_handle, SOL_SOCKET, SO_KEEPALIVE, (char*)&bKeepAlive, sizeof(bKeepAlive));

然后调整具体的参数,需要调用WSAIoctl

tcp_keepalive alive_in = {0};

tcp_keepalive alive_out = {0};

alive_in.keepalivetime = 5000;

alive_in.keepaliveinterval = 1000;

alive_in.onoff = TRUE;

unsigned long ulBytesReturn = 0;

nRet = WSAIoctl(socket_handle, SIO_KEEPALIVE_VALS, &alive_in, sizeof(alive_in), &alive_out, sizeof(alive_out), &ulBytesReturn, NULL, NULL);

开启Keepalive选项之后,对于使用IOCP模型的服务器端程序来说,一旦检测到连接断开,GetQueuedCompletionStatus函数将立即返回FALSE,使得服务器端能及时清除该连接、释放该连接相关的资源。对于使用 select模型的客户端来说,连接断开被探测到时,以recv目的阻塞在socket上的select方法将立即返回SOCKET_ERROR,从而得知连接已失效,客户端程序便有机会及时执行清除工作、提醒用户或重新连接。

你可能感兴趣的:(java检测tcp存活)