常用的 TCP KeepAlive 参数
转自:http://dola.xinfan.org/?p=359
我们知道 TCP 协议有检测连接状态的机制,当连接不活跃的时候,连接双方会通过一定的算法检测连接是否正常。这个机制就是 TCP 的 KeepAlive 算法。
如果不使用 KeepAlive 算法检测连接状态,会导致单方面断开连接后,另一方无法感知。比如 A 在用 recv 函数等待 B 发送数据,但这时候 B 已经失效,A 会一直等在 recv 函数上不能返回。
要启用 KeepAlive,我们要使用 setsockopt 函数来实现。在 Python 中是这么做的:
1
2
3
4
5
6
|
#!/usr/bin/env python import socket s = socket.socket() s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1 ) |
最后一个参数1表示启用 KeepAlive。程序会使用系统默认的参数进行连接状态检测。
在 Debian 操作系统中,默认在连接 idle 7200 秒(/proc/sys/net/ipv4/tcp_keepalive_time)后才发送第一个 KeepAlive 状态检测包,整整两个小时,着实有点长,对有些应用场景不太适合。因此,我们通常需要调整触发 KeepAlive 的 idle 时间间隔:
1
|
s.setsockopt(socket.SOL_TCP, socket.TCP_KEEPIDLE, 10 ) |
最后一个参数 10 表示在连接不活跃 10s 后开始 KeepAlive 检测。
开始 KeepAlive 检测之后,程序会每隔一定时间发送一次 KeepAlive 状态检测包,Debian 操作系统下默认是 75 秒(/proc/sys/net/ipv4/tcp_keepalive_intvl)发送一次,我们也可以在程序中定义这个发送间隔:
1
|
s.setsockopt(socket.SOL_TCP, socket.TCP_KEEPINTVL, 6 ) |
最后一个参数表示每隔 6s 发送一次。
连接的另一方收到 KeepAlive 状态检测包后会发送一个响应包,表示还活着。如果对方未及时发送响应包,程序会对失败次数进行记录,Debian 操作系统中如果连续 9 次(/proc/sys/net/ipv4/tcp_keepalive_probe)失败,会认为对方已经失效,会触发连接异常操作,中断所有正在进行的操作,比如 recv 会返回 -1,并设置 error code 为 Broken Pipe。当然,我们也可以在程序中定义允许失败的次数:
1
|
s.setsockopt(socket.SOL_TCP, socket.TCP_KEEPCNT, 3 ) |
在这个例子中,我们把它设置成了 3 次。
在 Linux 操作系统中,我们可以使用 netstat 工具使用 –timer 参数来查看当前系统中的 tcp 连接的 KeepAlive 状态:
1
2
3
4
5
6
7
8
|
# netstat -anplt --timer Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State PID /Program name Timer tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 2066 /sshd off (0.00 /0/0 ) tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN 2012 /mysqld off (0.00 /0/0 ) tcp 0 0 172.16.10.23:22 172.16.10.1:46726 ESTABLISHED 7280 /0 keepalive (5053.74 /0/0 ) tcp6 0 0 :::80 :::* LISTEN 7150 /apache2 off (0.00 /0/0 ) tcp6 0 0 :::22 :::* LISTEN 2066 /sshd off (0.00 /0/0 ) |