TCP keep-alive的三個參數
用man指令,可以檢視linux的tcp的參數:
man 7 tcp
其中keep-alive相關的參數有三個:
tcp_keepalive_intvl (integer; default: 75; since Linux 2.4)
The number of seconds between TCP keep-alive probes.
tcp_keepalive_probes (integer; default: 9; since Linux 2.2)
The maximum number of TCP keep-alive probes to send before giving up and killing the connection if no
response is obtained from the other end.
tcp_keepalive_time (integer; default: 7200; since Linux 2.2)
The number of seconds a connection needs to be idle before TCP begins sending out keep-alive probes. Keep-
alives are sent only when the SO_KEEPALIVE socket option is enabled. The default value is 7200 seconds (2
hours). An idle connection is terminated after approximately an additional 11 minutes (9 probes an interval
of 75 seconds apart) when keep-alive is enabled.
這些的預設配置值在/proc/sys/net/ipv4 目錄下可以找到。
可以直接用cat來檢視檔案的内容,就可以知道配置的值了。
也可以通過sysctl指令來檢視和修改:
# 查詢
cat /proc/sys/net/ipv4/tcp_keepalive_time
sysctl net.ipv4.tcp_keepalive_time
#修改
sysctl net.ipv4.tcp_keepalive_time=3600
上面三個是系統級的配置,在程式設計時有三個參數對應,可以覆寫掉系統的配置:
TCP_KEEPCNT 覆寫 tcp_keepalive_probes,預設9(次)
TCP_KEEPIDLE 覆寫 tcp_keepalive_time,預設7200(秒)
TCP_KEEPINTVL 覆寫 tcp_keepalive_intvl,預設75(秒)
```
## tcp keep-alive的本質
###TCP keep-alive probe
上面了解了tcp keep-alive的一些參數,下面來探究下其本質。
在遠端機器192.168.66.123上,用nc啟動一個TCP伺服器:
```bash
nc -l 9999
<div class="se-preview-section-delimiter"></div>
在本地機器上,用python建立一個socket去連接配接,并且用wireshark抓包分析
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
s.setsockopt(socket.SOL_TCP, socket.TCP_KEEPIDLE, 20)
s.setsockopt(socket.SOL_TCP, socket.TCP_KEEPINTVL, 1)
s.connect(('192.168.66.123', 9999))
上面的程式,設定了TCP_KEEPIDLE為20,TCP_KEEPINTVL為1,系統預設的tcp_keepalive_probes是9。
當網絡正常,不做幹擾時,wireshark抓包的資料是這樣的(注意看第二列Time):
可以看到,當3次握手完成之後,每隔20秒之後66.120發送了一個TCP Keep-Alive的資料包,然後66.123回應了一個TCP Keep-Alive ACK包。這個就是TCP keep-alive的實作原理了。
當發送了第一個TCP Keep-Alive包之後,撥掉192.168.66.123的網線,然後資料包是這樣子的:
可以看到,當遠端伺服器192.168.66.123網絡失去連接配接之後,本地機器(192.168.66.120)每隔一秒重發了9次tcp keep-alive probe,最終認為這個TCP連接配接已經失效,發了一個RST包給192.168.66.123。
在本地機器上,用python建立一個socket去連接配接,并且用wireshark抓包分析
```python
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
s.setsockopt(socket.SOL_TCP, socket.TCP_KEEPIDLE, 20)
s.setsockopt(socket.SOL_TCP, socket.TCP_KEEPINTVL, 1)
s.connect(('192.168.66.123', 9999))

當發送了第一個TCP Keep-Alive包之後,撥掉192.168.66.123的網線,然後資料包是這樣子的:
為什麼應用層需要heart beat/心跳包?
預設的tcp keep-alive逾時時間太長
預設是7200秒,也就是2個小時。
socks proxy會讓tcp keep-alive失效
socks協定隻管轉發TCP層具體的資料包,而不會轉發TCP協定内的實作細節的包(也做不到),
參考socks_proxy。
是以,一個應用如果使用了socks代理,那麼tcp keep-alive機制就失效了,是以應用要自己有心跳包。
socks proxy隻是一個例子,真實的網絡很複雜,可能會有各種原因讓tcp keep-alive失效。
移動網絡需要信令保活
前兩年,微信信令事件很火,搜尋下“微信 信令”或者“移動網絡 信令”可以查到很多相關文章。
這裡附上一個連結:
微信的大規模使用真的會過多占用信令,影響通訊穩定嗎?總結
- TCP keep-alive是通過在空閑時發送TCP Keep-Alive資料包,然後對方回應TCP Keep-Alive ACK來實作的。
- 為什麼需要heart beat/心跳包?因為tcp keep-alive不能滿足人們的實時性的要求,就是這麼簡單。