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