Linux TCP连接建立过程超时的参数调整

服务器

浏览数:66

2020-7-16

AD:资源代下载服务

1. 概述

github项目地址:https://github.com/superwujc

尊重原创,欢迎转载,注明出处:https://my.oschina.net/superwjc/blog/1819254

TCP的连接建立过程通常称为三次握手(three-way handshake),即客户端与服务端彼此交换用于建立连接的初始SYN segment与ACK。

连接建立过程中,任一端出现接收不到对端ACK的情况时,都将导致本端重传初始SYN segment,Linux内核为该情况设置了重传间隔与重传次数:

  1. 重传间隔:若当前为第N次重传,则与上一次发送或重传的间隔时间为2的(N -1)次方秒,但最长间隔不超过120秒;内核的TCP_TIMEOUT_INIT/TCP_RTO_MIN/TCP_RTO_MAX宏分别定义了间隔时间的初始值/最小值/最大值
  2. 重传次数:客户端由tcp_syn_retries指定,对应的proc文件为/proc/sys/net/ipv4/tcp_syn_retries,sysctl参数为net.ipv4.tcp_syn_retries;服务端由tcp_synack_retries指定,对应的proc文件为/proc/sys/net/ipv4/tcp_synack_retries,sysctl参数为net.ipv4.tcp_synack_retries

2. 示例

操作系统:CentOS Linux release 7.5.1804 (Core)

内核版本:3.10.0-862.2.3.el7.x86_64

服务端IP:22.99.22.111

客户端IP:22.99.22.101

示例程序详见 Linux TCP那些事儿之被动套接字(一)

服务端启动程序:

# ./tcp_server -b 1024 &

客户端启动程序:

# ./tcp_client -i 22.99.22.111 -p 8888 -n 1 &

服务端与客户端分别启动tcpdump观察连接情况:

# tcpdump -i eth0 -nn -S host 22.99.22.111 and host 22.99.22.101 and tcp

2.1 – 正常连接

服务端与客户端的tcpdump输出:

21:40:49.989951 IP 22.99.22.101.38118 > 22.99.22.111.8888: Flags [S], seq 231965702, win 29200, options [mss 1460,sackOK,TS val 11012209 ecr 0,nop,wscale 7], length 0
21:40:49.989998 IP 22.99.22.111.8888 > 22.99.22.101.38118: Flags [S.], seq 513997240, ack 231965703, win 28960, options [mss 1460,sackOK,TS val 14396437 ecr 11012209,nop,wscale 7], length 0
21:40:49.990223 IP 22.99.22.101.38118 > 22.99.22.111.8888: Flags [.], ack 513997241, win 229, options [nop,nop,TS val 11012210 ecr 14396437], length 0
21:40:49.991145 IP 22.99.22.101.38118 > 22.99.22.111.8888: Flags [S], seq 231965702, win 29200, options [mss 1460,sackOK,TS val 11012209 ecr 0,nop,wscale 7], length 0
21:40:49.991499 IP 22.99.22.111.8888 > 22.99.22.101.38118: Flags [S.], seq 513997240, ack 231965703, win 28960, options [mss 1460,sackOK,TS val 14396437 ecr 11012209,nop,wscale 7], length 0
21:40:49.991541 IP 22.99.22.101.38118 > 22.99.22.111.8888: Flags [.], ack 513997241, win 229, options [nop,nop,TS val 11012210 ecr 14396437], length 0

查看连接状态,两端均显示连接已建立

# ss -atn | grep 8888
LISTEN     1      128          *:8888                     *:*
ESTAB      0      0      22.99.22.111:8888               22.99.22.101:38118
# ss -atn | grep 8888
ESTAB      0      0      22.99.22.101:38118              22.99.22.111:8888

2.2 – 客户端超时

在服务端添加防火墙规则,丢弃向客户端发送的syn+ack

# iptables -I OUTPUT -p tcp --destination 22.99.22.101 --tcp-flags ALL ACK,SYN -j DROP
#
# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
DROP       tcp  --  anywhere             22.99.22.101         tcp flags:FIN,SYN,RST,PSH,ACK,URG/SYN,ACK

客户端设置重传次数,默认为6,修改为4

# cat /proc/sys/net/ipv4/tcp_syn_retries
6
# echo 4 > /proc/sys/net/ipv4/tcp_syn_retries
# cat /proc/sys/net/ipv4/tcp_syn_retries
4

再次启动服务端与客户端程序,两端的tcpdump输出均显示客户端发生了4次初始SYN的重传,每次间隔分别为1s/2s/4s/8s,总间隔为15s

21:49:29.425637 IP 22.99.22.101.38120 > 22.99.22.111.8888: Flags [S], seq 1034503734, win 29200, options [mss 1460,sackOK,TS val 11531645 ecr 0,nop,wscale 7], length 0
21:49:30.428747 IP 22.99.22.101.38120 > 22.99.22.111.8888: Flags [S], seq 1034503734, win 29200, options [mss 1460,sackOK,TS val 11532648 ecr 0,nop,wscale 7], length 0
21:49:32.433200 IP 22.99.22.101.38120 > 22.99.22.111.8888: Flags [S], seq 1034503734, win 29200, options [mss 1460,sackOK,TS val 11534652 ecr 0,nop,wscale 7], length 0
21:49:36.437044 IP 22.99.22.101.38120 > 22.99.22.111.8888: Flags [S], seq 1034503734, win 29200, options [mss 1460,sackOK,TS val 11538656 ecr 0,nop,wscale 7], length 0
21:49:44.454342 IP 22.99.22.101.38120 > 22.99.22.111.8888: Flags [S], seq 1034503734, win 29200, options [mss 1460,sackOK,TS val 11546673 ecr 0,nop,wscale 7], length 0
21:49:29.426515 IP 22.99.22.101.38120 > 22.99.22.111.8888: Flags [S], seq 1034503734, win 29200, options [mss 1460,sackOK,TS val 11531645 ecr 0,nop,wscale 7], length 0
21:49:30.429581 IP 22.99.22.101.38120 > 22.99.22.111.8888: Flags [S], seq 1034503734, win 29200, options [mss 1460,sackOK,TS val 11532648 ecr 0,nop,wscale 7], length 0
21:49:32.434015 IP 22.99.22.101.38120 > 22.99.22.111.8888: Flags [S], seq 1034503734, win 29200, options [mss 1460,sackOK,TS val 11534652 ecr 0,nop,wscale 7], length 0
21:49:36.437559 IP 22.99.22.101.38120 > 22.99.22.111.8888: Flags [S], seq 1034503734, win 29200, options [mss 1460,sackOK,TS val 11538656 ecr 0,nop,wscale 7], length 0
21:49:44.454826 IP 22.99.22.101.38120 > 22.99.22.111.8888: Flags [S], seq 1034503734, win 29200, options [mss 1460,sackOK,TS val 11546673 ecr 0,nop,wscale 7], length 0

查看连接状态,服务端的syn+ack由于被自身drop而一直处于LISTEN状态,客户端在重传期间处于SYN-SENT状态,且超过重传次数后因连接超时而返回

# ss -atn | grep 8888
LISTEN     0      128          *:8888                     *:*
# ss -atn | grep 8888
SYN-SENT   0      1      22.99.22.101:38120              22.99.22.111:8888
# connect() failed: Connection timed out

2.3 – 服务端超时

在客户端添加防火墙规则,丢弃向服务端发送的ack

# iptables -I OUTPUT -p tcp --destination 22.99.22.111 --dport 8888 --tcp-flags ALL ACK -j DROP
#
# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
DROP       tcp  --  anywhere             22.99.22.111         tcp dpt:ddi-tcp-1 flags:FIN,SYN,RST,PSH,ACK,URG/ACK

客户端设置重传次数,默认为5,修改为3

# sysctl net.ipv4.tcp_synack_retries
net.ipv4.tcp_synack_retries = 5
#
[root@localhost code]# sysctl -w net.ipv4.tcp_synack_retries=3
net.ipv4.tcp_synack_retries = 3
#
# sysctl net.ipv4.tcp_synack_retries
net.ipv4.tcp_synack_retries = 3

再次启动服务端与客户端程序,两端的tcpdump输出均显示服务端发生了3次初始SYN的重传,每次间隔分别为1s/2s/4s,总间隔为7s

22:03:56.982987 IP 22.99.22.101.38122 > 22.99.22.111.8888: Flags [S], seq 985103784, win 29200, options [mss 1460,sackOK,TS val 12399201 ecr 0,nop,wscale 7], length 0
22:03:56.983034 IP 22.99.22.111.8888 > 22.99.22.101.38122: Flags [S.], seq 703914964, ack 985103785, win 28960, options [mss 1460,sackOK,TS val 15783430 ecr 12399201,nop,wscale 7], length 0
22:03:57.985014 IP 22.99.22.111.8888 > 22.99.22.101.38122: Flags [S.], seq 703914964, ack 985103785, win 28960, options [mss 1460,sackOK,TS val 15784432 ecr 12399201,nop,wscale 7], length 0
22:03:59.993905 IP 22.99.22.111.8888 > 22.99.22.101.38122: Flags [S.], seq 703914964, ack 985103785, win 28960, options [mss 1460,sackOK,TS val 15786441 ecr 12399201,nop,wscale 7], length 0
22:04:04.008496 IP 22.99.22.111.8888 > 22.99.22.101.38122: Flags [S.], seq 703914964, ack 985103785, win 28960, options [mss 1460,sackOK,TS val 15790456 ecr 12399201,nop,wscale 7], length 0
22:03:56.983313 IP 22.99.22.101.38122 > 22.99.22.111.8888: Flags [S], seq 985103784, win 29200, options [mss 1460,sackOK,TS val 12399201 ecr 0,nop,wscale 7], length 0
22:03:56.983746 IP 22.99.22.111.8888 > 22.99.22.101.38122: Flags [S.], seq 703914964, ack 985103785, win 28960, options [mss 1460,sackOK,TS val 15783430 ecr 12399201,nop,wscale 7], length 0
22:03:57.985870 IP 22.99.22.111.8888 > 22.99.22.101.38122: Flags [S.], seq 703914964, ack 985103785, win 28960, options [mss 1460,sackOK,TS val 15784432 ecr 12399201,nop,wscale 7], length 0
22:03:59.994857 IP 22.99.22.111.8888 > 22.99.22.101.38122: Flags [S.], seq 703914964, ack 985103785, win 28960, options [mss 1460,sackOK,TS val 15786441 ecr 12399201,nop,wscale 7], length 0
22:04:04.009283 IP 22.99.22.111.8888 > 22.99.22.101.38122: Flags [S.], seq 703914964, ack 985103785, win 28960, options [mss 1460,sackOK,TS val 15790456 ecr 12399201,nop,wscale 7], length 0

查看连接状态,服务端的初始SYN被客户端丢弃而在重传期间一直处于SYN-RECV状态,客户端已接收到服务端对初始SYN的ACK确认而处于ESTAB状态,导致半开(half-open)连接

# ss -atn | grep 8888
LISTEN     0      128          *:8888                     *:*
SYN-RECV   0      0      22.99.22.111%if355612354:8888               22.99.22.101:38122
# ss -atn | grep 8888
ESTAB      0      0      22.99.22.101:38122              22.99.22.111:8888