当前位置:首页 > 公众号精选 > 小林coding
[导读]之前写过 TCP 三次握手和四次挥手过程中,途中某一步的报文丢失会发生什么的文章。

大家好,我是小林。

之前写过 TCP 三次握手和四次挥手过程中,途中某一步的报文丢失会发生什么的文章。

当时,主要是文字描述,可能不太好记忆,所以我针对每一步的异常情况,重新画了图,方便大家理解和记忆。

发车!

TCP 三次握手丢包情况

第一次握手丢失了,会发生什么?

当客户端想和服务端建立 TCP 连接的时候,首先第一个发的就是 SYN 报文,然后进入到SYN_SENT状态。

在这之后,如果客户端迟迟收不到服务端的 SYN-ACK 报文(第二次握手),就会触发「超时重传」机制,重传 SYN 报文,而且重传的 SYN 报文的序列号都是一样的

不同版本的操作系统可能超时时间不同,有的 1 秒的,也有 3 秒的,这个超时时间是写死在内核里的,如果想要更改则需要重新编译内核,比较麻烦。

当客户端在 1 秒后没收到服务端的 SYN-ACK 报文后,客户端就会重发 SYN 报文,那到底重发几次呢?

在 Linux 里,客户端的 SYN 报文最大重传次数由tcp_syn_retries内核参数控制,这个参数是可以自定义的,默认值一般是 5。

# cat /proc/sys/net/ipv4/tcp_syn_retries 5

通常,第一次超时重传是在 1 秒后,第二次超时重传是在 2 秒,第三次超时重传是在 4 秒后,第四次超时重传是在 8 秒后,第五次是在超时重传 16 秒后。没错,每次超时的时间是上一次的 2 倍

当第五次超时重传后,会继续等待 32 秒,如果服务端仍然没有回应 ACK,客户端就不再发送 SYN 包,然后断开 TCP 连接。

所以,总耗时是 1+2+4+8+16+32=63 秒,大约 1 分钟左右。

举个例子,假设 tcp_syn_retries 参数值为 3,那么当客户端的 SYN 报文一直在网络中丢失时,会发生下图的过程:

具体过程:

  • 当客户端超时重传 3 次 SYN 报文后,由于  tcp_syn_retries 为 3,已达到最大重传次数,于是再等待一段时间(时间为上一次超时时间的 2 倍),如果还是没能收到服务端的第二次握手(SYN-ACK 报文),那么客户端就会断开连接。

第二次握手丢失了,会发生什么?

当服务端收到客户端的第一次握手后,就会回 SYN-ACK 报文给客户端,这个就是第二次握手,此时服务端会进入SYN_RCVD状态。

第二次握手的SYN-ACK报文其实有两个目的 :

  • 第二次握手里的 ACK, 是对第一次握手的确认报文;
  • 第二次握手里的 SYN,是服务端发起建立 TCP 连接的报文;

所以,如果第二次握手丢了,就会发生比较有意思的事情,具体会怎么样呢?

因为第二次握手报文里是包含对客户端的第一次握手的 ACK 确认报文,所以,如果客户端迟迟没有收到第二次握手,那么客户端就觉得可能自己的 SYN 报文(第一次握手)丢失了,于是客户端就会触发超时重传机制,重传 SYN 报文

然后,因为第二次握手中包含服务端的 SYN 报文,所以当客户端收到后,需要给服务端发送 ACK 确认报文(第三次握手),服务端才会认为该 SYN 报文被客户端收到了。

那么,如果第二次握手丢失了,服务端就收不到第三次握手,于是服务端这边会触发超时重传机制,重传 SYN-ACK 报文

在 Linux 下,SYN-ACK 报文的最大重传次数由tcp_synack_retries内核参数决定,默认值是 5。

# cat /proc/sys/net/ipv4/tcp_synack_retries 5

因此,当第二次握手丢失了,客户端和服务端都会重传:

  • 客户端会重传 SYN 报文,也就是第一次握手,最大重传次数由tcp_syn_retries内核参数决定;
  • 服务端会重传 SYN-ACK 报文,也就是第二次握手,最大重传次数由tcp_synack_retries内核参数决定。

举个例子,假设 tcp_syn_retries  参数值为 1,tcp_synack_retries 参数值为 2,那么当第二次握手一直丢失时,发生的过程如下图:

具体过程:

  • 当客户端超时重传 1 次 SYN 报文后,由于  tcp_syn_retries 为 1,已达到最大重传次数,于是再等待一段时间(时间为上一次超时时间的 2 倍),如果还是没能收到服务端的第二次握手(SYN-ACK 报文),那么客户端就会断开连接。
  • 当服务端超时重传 2 次 SYN-ACK 报文后,由于 tcp_synack_retries 为 2,已达到最大重传次数,于是再等待一段时间(时间为上一次超时时间的 2 倍),如果还是没能收到客户端的第三次握手(ACK 报文),那么服务端就会断开连接。

第三次握手丢失了,会发生什么?

客户端收到服务端的 SYN-ACK 报文后,就会给服务端回一个 ACK 报文,也就是第三次握手,此时客户端状态进入到ESTABLISH状态。

因为这个第三次握手的 ACK 是对第二次握手的 SYN 的确认报文,所以当第三次握手丢失了,如果服务端那一方迟迟收不到这个确认报文,就会触发超时重传机制,重传 SYN-ACK 报文,直到收到第三次握手,或者达到最大重传次数。

注意,ACK 报文是不会有重传的,当 ACK 丢失了,就由对方重传对应的报文

举个例子,假设 tcp_synack_retries 参数值为 2,那么当第三次握手一直丢失时,发生的过程如下图:

具体过程:

  • 当服务端超时重传 2 次 SYN-ACK 报文后,由于 tcp_synack_retries 为 2,已达到最大重传次数,于是再等待一段时间(时间为上一次超时时间的 2 倍),如果还是没能收到客户端的第三次握手(ACK 报文),那么服务端就会断开连接。

TCP 四次挥手丢包情况

第一次挥手丢失了,会发生什么?

当客户端(主动关闭方)调用 close 函数后,就会向服务端发送 FIN 报文,试图与服务端断开连接,此时客户端的连接进入到FIN_WAIT_1状态。

正常情况下,如果能及时收到服务端(被动关闭方)的 ACK,则会很快变为FIN_WAIT2状态。

如果第一次挥手丢失了,那么客户端迟迟收不到被动方的 ACK 的话,也就会触发超时重传机制,重传 FIN 报文,重发次数由tcp_orphan_retries参数控制。

当客户端重传 FIN 报文的次数超过tcp_orphan_retries后,就不再发送 FIN 报文,则会在等待一段时间(时间为上一次超时时间的 2 倍),如果还是没能收到第二次挥手,那么直接进入到close状态。

举个例子,假设 tcp_orphan_retries 参数值为 3,当第一次挥手一直丢失时,发生的过程如下图:

具体过程:

  • 当客户端超时重传 3 次 FIN 报文后,由于 tcp_orphan_retries 为 3,已达到最大重传次数,于是再等待一段时间(时间为上一次超时时间的 2 倍),如果还是没能收到服务端的第二次挥手(ACK报文),那么客户端就会断开连接。

第二次挥手丢失了,会发生什么?

当服务端收到客户端的第一次挥手后,就会先回一个 ACK 确认报文,此时服务端的连接进入到CLOSE_WAIT状态。

在前面我们也提了,ACK 报文是不会重传的,所以如果服务端的第二次挥手丢失了,客户端就会触发超时重传机制,重传 FIN 报文,直到收到服务端的第二次挥手,或者达到最大的重传次数。

举个例子,假设 tcp_orphan_retries 参数值为 2,当第二次挥手一直丢失时,发生的过程如下图:

具体过程:

  • 当客户端超时重传 2 次 FIN 报文后,由于 tcp_orphan_retries 为 2,已达到最大重传次数,于是再等待一段时间(时间为上一次超时时间的 2 倍),如果还是没能收到服务端的第二次挥手(ACK 报文),那么客户端就会断开连接。

这里提一下,当客户端收到第二次挥手,也就是收到服务端发送的 ACK 报文后,客户端就会处于FIN_WAIT2状态,在这个状态需要等服务端发送第三次挥手,也就是服务端的 FIN 报文。

对于 close 函数关闭的连接,由于无法再发送和接收数据,所以FIN_WAIT2状态不可以持续太久,而tcp_fin_timeout控制了这个状态下连接的持续时长,默认值是 60 秒。

这意味着对于调用 close 关闭的连接,如果在 60 秒后还没有收到 FIN 报文,客户端(主动关闭方)的连接就会直接关闭,如下图:

但是注意,如果主动关闭方使用 shutdown 函数关闭连接,指定了只关闭发送方向,而接收方向并没有关闭,那么意味着主动关闭方还是可以接收数据的。

此时,如果主动关闭方一直没收到第三次挥手,那么主动关闭方的连接将会一直处于FIN_WAIT2状态(tcp_fin_timeout无法控制 shutdown 关闭的连接)。如下图:

第三次挥手丢失了,会发生什么?

当服务端(被动关闭方)收到客户端(主动关闭方)的 FIN 报文后,内核会自动回复 ACK,同时连接处于CLOSE_WAIT状态,顾名思义,它表示等待应用进程调用 close 函数关闭连接。

此时,内核是没有权利替代进程关闭连接,必须由进程主动调用 close 函数来触发服务端发送 FIN 报文。

服务端处于 CLOSE_WAIT 状态时,调用了 close 函数,内核就会发出 FIN 报文,同时连接进入 LAST_ACK 状态,等待客户端返回 ACK 来确认连接关闭。

如果迟迟收不到这个 ACK,服务端就会重发 FIN 报文,重发次数仍然由tcp_orphan_retries 参数控制,这与客户端重发 FIN 报文的重传次数控制方式是一样的。

举个例子,假设tcp_orphan_retries = 3,当第三次挥手一直丢失时,发生的过程如下图:

具体过程:

  • 当服务端重传第三次挥手报文的次数达到了 3 次后,由于 tcp_orphan_retries 为 3,达到了重传最大次数,于是再等待一段时间(时间为上一次超时时间的 2 倍),如果还是没能收到客户端的第四次挥手(ACK报文),那么服务端就会断开连接。
  • 客户端因为是通过 close 函数关闭连接的,处于 FIN_WAIT_2 状态是有时长限制的,如果 tcp_fin_timeout 时间内还是没能收到服务端的第三次挥手(FIN 报文),那么客户端就会断开连接。

第四次挥手丢失了,会发生什么?

当客户端收到服务端的第三次挥手的 FIN 报文后,就会回 ACK 报文,也就是第四次挥手,此时客户端连接进入TIME_WAIT状态。

在 Linux 系统,TIME_WAIT 状态会持续 2MSL 后才会进入关闭状态。

然后,服务端(被动关闭方)没有收到 ACK 报文前,还是处于 LAST_ACK 状态。

如果第四次挥手的 ACK 报文没有到达服务端,服务端就会重发 FIN 报文,重发次数仍然由前面介绍过的tcp_orphan_retries参数控制。

举个例子,假设 tcp_orphan_retries 为 2,当第四次挥手一直丢失时,发生的过程如下:

具体过程:

  • 当服务端重传第三次挥手报文达到 2 时,由于 tcp_orphan_retries 为 2, 达到了最大重传次数,于是再等待一段时间(时间为上一次超时时间的 2 倍),如果还是没能收到客户端的第四次挥手(ACK 报文),那么服务端就会断开连接。
  • 客户端在收到第三次挥手后,就会进入 TIME_WAIT 状态,开启时长为 2MSL 的定时器,如果途中再次收到第三次挥手(FIN 报文)后,就会重置定时器,当等待 2MSL 时长后,客户端就会断开连接。

完!

怎么样,这下很清晰了吧

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

TCP 是基于连接的数据流的协议,先建立连接再进行通信,而且在通信过程中会检查数据是否发送成功。优点就是保证数据的完整性和准确性,缺点就是效率较低。

关键字: TCP 数据流 协议

在进行socket通信开发时,一般会用到TCP或UDP这两种传输层协议,UDP(User Datagram Protocol)是一种面向无连接的协议,在数据发送前,不需要提前建立连接,它可以更高效地传输数据,但可靠性无法...

关键字: socket TCP UDP

客户端主动调用关闭连接的函数,于是就会发送 FIN 报文,这个 FIN 报文代表客户端不会再发送数据了,进入 FIN_WAIT_1 状态;

关键字: 客户端 TCP

事情从一个健身教练说起吧。李东,自称亚健康终结者,尝试使用互联网的模式拓展自己的业务。在某款新开发的聊天软件琛琛上发布广告。键盘说来就来。疯狂发送"李东",回车发送!,"亚健康终结者",再回车发送!还记得四层网络协议长什...

关键字: TCP UDP 数据包 应用层

传输控制协议(TCP,Transmission Control Protocol)是为了在不可靠的互联网络上提供可靠的端到端字节流而专门设计的一个传输协议。

关键字: TCP

IP是Internet Protocol(网际互连协议)的缩写,是TCP/IP体系中的网络层协议。设计IP的目的是提高网络的可扩展性:一是解决互联网问题,实现大规模、异构网络的互联互通;二是分割顶层网络应用和底层网络技术...

关键字: IP TCP 主机

Internet 协议集支持一个无连接的传输协议,该协议称为用户数据包协议(UDP,User Datagram Protocol)。UDP 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据包的方法。RFC 7...

关键字: UDP TCP IP

选路协议,支持路由器封装并发送的网络通信语言。选路协议的例子有以太网、AppleTalk、TCP/IP、帧中继和X.25。以太网(Ethernet)指的是由Xerox公司创建并由Xerox、Intel和DEC公司联合开发...

关键字: 选路协议 TCP IP

超文本传输协议(Hyper Text Transfer Protocol,HTTP)是一个简单的请求-响应协议,它通常运行在TCP之上。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。请求和响应消息的头以...

关键字: HTTP WEB TCP

路由器(Router)是连接两个或多个网络的硬件设备,在网络间起网关的作用,是读取每一个数据包中的地址然后决定如何传送的专用智能性的网络设备。它能够理解不同的协议,例如某个局域网使用的以太网协议,因特网使用的TCP/IP...

关键字: 路由器 TCP IP
关闭