轉自: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
)
|
