TCP Keep-Alive

687 阅读2分钟

TCP socket 连接,自带超时的保活机制。

所以套接字不会保持永久连接,有可能在几个小时后,超时断开。

1. 介绍

TCP 套接字包括两个对等端。当一端准备断开连接时,它将发送 FIN 给另一端。

另一端收到 FIN 后,响应 ACK 给对端后随即再发送 FIN 给对端。一端收到 ACK 和 FIN 标志的报文后,TCP 套接字断开。

上述描述是在理想状态下的,四次挥手断开连接。但是,如果一端因为网络原因或者自身机器重启等因素,另一端无法收到 FIN。那么 TCP 套接字改如何断开呢,这就是 Keep-Alive 的工作之处了。

2. Keep-Alive 工作原理

首先,介绍几个 Keep-Alive 工作时候用到的参数。

  • tcp_keepalive_time
    • default 7200 seconds
  • tcp_keepalive_probes
    • default 9
  • tcp_keepalive_intvl
    • default 75 seconds

1. 客户端建立 TCP 连接。

2. 如果连接在 tcp_keepalive_time 时间段没有数据活动,那么客户端将发送一个 ACK 的空包给对端。

3. 服务端需要响应一个 ACK 给客户端

  • No
    1. 等候 tcp_keepalive_intval 秒,然后再发送一个 ACK。
    2. 重复发送 ACK 探测包,直到发送数量等于 tcp_keepalive_probes
    3. 如果还没有收到任何回复,那么客户端发送 RST,结束连接。
  • Yes
    回到步骤 2.

整个处理过程在绝大多数操作系统上都是默认生效的,因此一个 TCP 连接 7200s + 75 * 9s,

约 2 小时 11 分钟没有数据活动,此连接将会被清除

3. 注意

对于连接数量很大的应用程序,如数据库。清除一个不活跃的 TCP 连接,需要 2 小时多,显然是不合理的。

Keep-Alive is Optional

根据 RFC 11224.2.3.6,中继或响应 TCP Keep-Alive 包是可选的

4. 修改 TCP 超时参数

Linux

# 查看配置,单位 秒
cat /proc/sys/net/ipv4/tcp_keepalive_time
cat /proc/sys/net/ipv4/tcp_keepalive_probes
cat /proc/sys/net/ipv4/tcp_keepalive_intvl

# 修改配置,临时生效(重启失效)
echo 180 > /proc/sys/net/ipv4/tcp_keepalive_time
echo 3 > /proc/sys/net/ipv4/tcp_keepalive_probes
echo 10 > /proc/sys/net/ipv4/tcp_keepalive_intvl

# 修改配置,永久生效
sysctl -w net.ipv4.tcp_keepalive_time=180 \
          net.ipv4.tcp_keepalive_probes=3 \
          net.ipv4.tcp_keepalive_intvl=10

Mac OS X

# 查看配置,单位 毫秒
$ sysctl net.inet.tcp | grep -E "keepidle|keepintvl|keepcnt"
  net.inet.tcp.keepidle: 7200000
  net.inet.tcp.keepintvl: 75000
  net.inet.tcp.keepcnt: 8

# 修改配置
sysctl -w net.inet.tcp.keepidle=180000 net.inet.tcp.keepcnt=3 net.inet.tcp.keepintvl=10000

Windows

\HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\TCPIP\Parameters

4. 附注

FIN 和 RST 区别

FIN 是用来协商关闭 TCP Socket

RST 是用来单方面关闭 TCP Socket

Websocket ping-pong 间隔

websocket 基于 短连接的 HTTP/1.1,及时携带 Connection:keep-alive。一个典型的 HTTP/1.1 连接,将会在 30 - 120s 之间关闭。

因此,如果 Websocket 在 30s 内没有数据活动,代理可能过早的将其断开连接。

鉴于此,大部分开源的 Websocket 都会维持一个 20s 的 ping-pong

参考

websockets.readthedocs.io/en/stable/t…

stackoverflow.com/questions/1…