TCP握手挥手详解

本文系统版本:

[root@localhost ~]# cat /proc/version
Linux version 4.18.0-348.el8.x86_64 (mockbuild@kbuilder.bsys.centos.org) (gcc version 8.5.0 20210514 (Red Hat 8.5.0-3) (GCC)) #1 SMP Tue Oct 19 15:14:17 UTC 2021

下载链接:http://mirrors.aliyun.com/centos/8.5.2111/isos/x86_64/CentOS-8.5.2111-x86_64-dvd1.iso

本文引用内核代码文档版本:Linux-4.18.0-348.2.1.el8_5

文档路径:Documentation\networking\ip-sysctl.txt

下载链接:https://vault.centos.org/8.5.2111/BaseOS/Source/SPackages/kernel-4.18.0-348.2.1.el8_5.src.rpm


握手过程

  1. client向server请求连接,SYN置为1,Seq为随机生成的ISN (最大不超过4,294,967,295) ,从CLOSE进入SYN_SENT状态;

  2. server收到后回复确认,SYN与ACK置为1,序列号为server随机生成的ISN (最大不超过4,294,967,295) ,确认号设为client的ISN+1,从LISTEN进入SYN-RCVD状态;

  3. client收到后,将ACK置为1,序列号为client的ISN+1,确认号为server的ISN+1,进入ESTABLISHED状态。server收到此确认报文后也进入ESTABLISHED状态。

挥手过程

  1. client向server请求断开连接,FIN置为1,ACK也置为1(回复上次数据包),序列号为上次接收的数据包中的确认号,确认号为上一个接收的数据包中的序列号+发送的数据长度,从ESTABLISHED状态到FIN_WAIT_1状态;

  2. server收到后回复确认,如果还有数据则ACK置为1,序列号与确认号规律同1,从ESTABLISHED进入CLOSE_WAIT状态;client收到后进入FIN_WAIT_2状态,继续接收server传来的数据。

  3. server数据发完后请求断开连接,FIN置为1,ACK也置为1(回复上次数据包),序列号与确认号规律同1,进入LACK_ACK状态。

  4. client收到后回复确认,ACK置为1,序列号与确认号规律同1,进入TIME_WAIT状态,默认持续2MSL后进入CLOSE状态,server收到回复后进入CLOSE状态。

在实际抓包过程中往往只会有3次,这是因为2次挥手时server已经没有数据需要发送了,所以2与3次挥手合并,将FIN与ACK同时置为1回复给client。

挥手过程的常见问题

为什么TIME_WAIT持续2MSL?

MSL,英文全称Maximum Segment Lifetime,中文全称最大分段存活时间,1MSL是TCP包从发出到确定丢失的时间。2MSL一方面可以保证如果client发出的最后一次握手产生异常未到达对端的话,有较为充足的时间让cleint收到超时重传的FIN包,另一方面是保证本次TCP连接产生所有数据包都在网络中消失,从而不会影响到新的TCP连接。

服务器存在大量TIME_WAIT怎么办?

首先这个场景一般是短连接高并发,所以积累了大量的TIME_WAIT连接,系统层面的解决方案是调整对应的配置参数,应用层面是将短链接调整为长连接,并且及时关闭。以下是相关参数(着重说明1):

tcp_max_tw_buckets

此参数表示系统同时保持的TIME_WAIT数量,默认值会随之系统内存的变化而变化,1G内存的情况下为4096,之后每增加1G,默认值乘2,即2G为8192,3G为16384,以此类推。此情况下可以适当调高此参数。

tcp_tw_reuse

此参数设为1是全局复用TIME_WAIT状态的socket。默认值为2,仅允许环回通信时复用。

以下是Linux内核代码文档中的相关参数与英文说明。

tcp_max_tw_buckets - INTEGER
    Maximal number of timewait sockets held by system simultaneously.
    If this number is exceeded time-wait socket is immediately destroyed
    and warning is printed. This limit exists only to prevent
    simple DoS attacks, you _must_ not lower the limit artificially,
    but rather increase it (probably, after increasing installed memory),
    if network conditions require more than default value.
    
tcp_tw_reuse - INTEGER
    Enable reuse of TIME-WAIT sockets for new connections when it is
    safe from protocol viewpoint.
    0 - disable
    1 - global enable
    2 - enable for loopback traffic only
    It should not be changed without advice/request of technical
    experts.
    Default: 2

临时修改:

echo "x" > /proc/sys/net/ipv4/tcp_max_tw_buckets
echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse

永久修改:

echo "net.ipv4.tcp_max_tw_buckets=x" >> /etc/sysctl.conf #根据情况适当调整
echo "net.ipv4.tcp_tw_reuse=1" >> /etc/sysctl.conf
sysctl -p

握手挥手的异常处理

TCP握手挥手的过程已经清楚了,但现实的网络环境错综复杂,常常会产生异常(丢包或由于较高延迟而导致数据迟到),TCP作为一个较为可靠的协议,在这方面也有相应的解决方法。

握手异常处理

第一次握手,SYN包丢失,未在指定时间内收到对方发来的SYN+ACK包,则根据tcp_syn_retries参数重发,直至收到回复或达到最大重传次数。

第二次握手,SYN+ACK包丢失,这个较为特殊,client由于没收到server对第一次握手的ACK,根据tcp_syn_retries参数超时重传,server由于没收到client对第二次握手的ACK,根据tcp_synack_retries参数超时重传,直至收到回复或达到最大重传次数。

第三次握手,ACK包是不会重传的,对端在指定时间内没有收到的话会超时重传SYN+ACK。如果达到最大重传次数,却依然没有收到ACK包,则进入ClOSE状态。此时client以为TCP连接已建立,开始发送数据包,server收到后会回复Rst,client收到后一般会看到个connection reset报错(见拓展1),随即关闭TCP连接。

具体参数说明

cat /proc/sys/net/ipv4/tcp_syn_retries
6
cat /proc/sys/net/ipv4/tcp_synack_retries
5

间隔时间采用指数退避算法,不同系统可能起始重发间隔时间不一样,在RFC 6298中为1秒,RFC 1122中该值为3秒,如果想更改,需重新编译内核。Centos8默认是1秒。

tcp_syn_retries默认值为6(老版本中为5,如4.19.217),也就是重发6次,重发间隔时间分别为1、2、4、8、16、32和64共127秒。tcp_synack_retries的默认值为5,间隔为1、2、4、8、16和32共63秒。

内核源码中参数的相关说明

tcp_syn_retries - INTEGER
    Number of times initial SYNs for an active TCP connection attempt
    will be retransmitted. Should not be higher than 127. Default value
    is 6, which corresponds to 63seconds till the last retransmission
    with the current initial RTO of 1second. With this the final timeout
    for an active TCP connection attempt will happen after 127seconds.
​
tcp_synack_retries - INTEGER
    Number of times SYNACKs for a passive TCP connection attempt will
    be retransmitted. Should not be higher than 255. Default value
    is 5, which corresponds to 31seconds till the last retransmission
    with the current initial RTO of 1second. With this the final timeout
    for a passive TCP connection will happen after 63seconds.

挥手异常处理

第一次挥手,FIN包丢失,如果未在指定时间内收到ACK,则根据tcp_orphan_retries参数重发,直至收到回复或达到最大重传次数直接Close;

第二次挥手,ACK包丢失,由于Client未在指定时间收到ACK,则根据tcp_orphan_retries参数重发,直至收到回复或达到最大重传次数直接Close;

第三次挥手,FIN包丢失,如果未在指定时间内收到ACK,则根据tcp_orphan_retries参数重发,直至收到回复或达到最大重传次数直接Close;Client端收到第二次挥手后会进入FIN_WAIT2状态,此状态根据tcp_fin_timeout保持状态时间,若在参数时间内未接到对端FIN则直接Close。

第四次挥手,ACK包丢失,由于server未在指定时间内收到ACK,则根据tcp_orphan_retries参数重发,直至收到回复或达到最大重传次数直接Close;

具体参数说明

cat /proc/sys/net/ipv4/tcp_orphan_retries
0
cat /proc/sys/net/ipv4/tcp_fin_timeout
60

tcp_orphan_retries的默认参数为0,也就是FIN包默认不进行重传。tcp_fin_timeout的默认参数为60,即FIN_TIMEWAIT2时间默认持续60s。

内核源码中参数的相关说明

tcp_orphan_retries - INTEGER
    This value influences the timeout of a locally closed TCP connection,
    when RTO retransmissions remain unacknowledged.
    See tcp_retries2 for more details.
​
tcp_fin_timeout - INTEGER
    The length of time an orphaned (no longer referenced by any
    application) connection will remain in the FIN_WAIT_2 state
    before it is aborted at the local end.  While a perfectly
    valid "receive only" state for an un-orphaned connection, an
    orphaned connection in FIN_WAIT_2 state could otherwise wait
    forever for the remote to close its end of the connection.
    Cf. tcp_max_orphans
    Default: 60 seconds

【着重说明1】此版本已无tcp_tw_recycle参数。

【拓展1】TCP连接常见的报错与原因:

        1. Connection reset

            server端由于某种原因关闭了连接,而client依然在读写数据,server回复RST包,产生此报错。

        2. Connection refused

            可能的原因有三个:

             1. server端口没开;

             2. 防火墙未放行;

             3. 半连接队列溢出。

        3. Connection reset by peer

        当本端收到远端传来的RST后,内核默认此连接已经关闭,但应用层依然尝试去执行读操作,会产生此报错。

        4. Broken pipe

        在第三种情况下应用层尝试去执行写操作,会产生此报错。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值