TCP 三次握手、四次挥手过程
TCP 三次握手、四次挥手过程
关于 TCP 的握手及挥手过程有点模糊。这里回顾下。
1、TCP报文字段含义
(1)seq:序号,用来标记数据段的顺序,TCP 把连接中发送的所有数据字节都编上一个序号,第一个字节的编号由本地随机产生。
(2)ack:确认号,是期望收到对方的下一个报文段的数据的第一个字节的seq序号;只有 ACK 标志位为1时,确认序号字段才有效,ack = seq+1。
(3)标志位:6个标志位,URG、ACK、PSH、RST、SYN、FIN(置1时有效)。
- URG:紧急指针有效。
- ACK:确认序号有效。
- PSH:接收方应该尽快将这个报文交给应用层。
- RST:复位,对方要求重新建立连接。
- SYN:表示一个连接请求或连接接收报文。
- FIN: 释放一个连接。
2、三次握手(建立连接)
(1)第一次握手:
客户端主动向服务端发送请求建立连接的报文,并进入同步已发送状态;SYN = 1 表示连接请求,seq = x 表示起始序列号,x表示一个随机数,通常为1。(SYN=1,seq=x)
(2)第二次握手:
服务端收到客户端的报文之后,返回一段确认接收到请求报文并同意创建新连接的报文,并进入同步收到状态。(SYN=1, ACK=1, seq=y, ack=x+1)
(3)第三次握手:
客户端接收到服务端的确认报文之后,也返回一段确认报文给服务端表示自己已收到确认报文并进入建立连接状态,服务端收到确认报文后也进入建立连接状态,此时双方成功建立 TCP 连接。(ACK=1, seq=x+1, ack=y+1)
注 :双方的确认号 ack 和序号 seq 的值,都是在彼此 ack 和 seq 值的基础上进行计算的,这样做保证了 TCP 报文传输的连贯性。一旦出现某一方发出的 TCP 报文丢失,便无法继续"握手",以此确保了"三次握手"的顺利完成。
3、四次挥手(断开连接)
(1)第一次挥手:
数据传输完毕,客户端想要释放连接(没有数据需要传输给服务端了),于是向服务端发送一段 TCP 报文请求释放连接,然后进入终止等待状态一。并且停止在客户端到服务端方向上发送数据,但是客户端仍然能接收从服务端传输过来的数据。FIN=1 表示请求释放连接, u为随机生成的起始报文段序号(FIN=1,seq=u)
(2)第二次挥手:
服务端收到连接释放报文,立即发出确认报文,表示接收到客户端发送的释放连接的请求,并进入关闭等待状态。(ACK=1,seq=v,ack=u+1)
(3)第三次挥手:
服务端自从发出 ACK 确认报文之后,经过了关闭等待阶段,做好了释放服务器端到客户端方向上的连接准备,再次向客户端发出一段TCP报文表示已经准备好释放连接了(没有数据需要传输给客户端了),然后进入最后确认状态。(FIN=1,ACK=1,seq=w,ack=u+1)
(4)第四次挥手:
客户端收到从服务器端发出的 TCP 报文,确认了服务器端已做好释放连接的准备,于是再次向服务端发送报文表示接收到服务端准备好释放连接的信号,并进入 TIME-WAIT 阶段等待 2MSL ( 最大报文生存时间) 后再断开连接,服务端收到最终确认报文后立即断开连接,双方断开 TCP 连接。(ACK=1,seq=u+1,ack=w+1)
注:与“三次挥手”一样,在客户端与服务器端传输的 TCP 报文中,双方的确认号 ack 和序号 seq 的值,都是在彼此 ack 和 seq 值的基础上进行计算的,这样做保证了 TCP 报文传输的连贯性,一旦出现某一方发出的 TCP 报文丢失,便无法继续"挥手",以此确保了"四次挥手"的顺利完成。
4、常见面试题
1.为什么“握手”是三次,“挥手”却要四次?
建立连接时,被动方服务器端结束 CLOSED 阶段进入“握手”阶段并不需要任何准备,可以一起返回 SYN 和 ACK 报文,开始建立连接。而释放连接时,被动方服务端,然收到主动方客户端释放连接的请求时并不能立即释放连接,因为还有必要的数据需要处理,所以服务器只能先先返回 ACK 确认收到报文,经过 CLOSE-WAIT 阶段准备好释放连接(处理完数据之后)之后,才能返回FIN释放连接报文。
2.为什么客户端在TIME-WAIT阶段要等 2MSL?
主要目的是确认服务器端是否收到客户端发出的最终 ACK 确认报文。
当客户端发出最后的 ACK 确认报文时,并不能确定服务器端能够收到该段报文。所以客户端在发送完 ACK 确认报文之后,会设置一个时长为 2MSL 的计时器。MSL 指的是:一段TCP报文在传输过程中的最大生命周期。2MSL 即是一个发送和一个回复所需的最大时间。
服务端如果在 1MSL 内没有收到客户端发出的最终 ACK确认 报文(说明最终确认报文丢失了),就会再次向客户端发出 FIN 报文。
如果客户端在 2MSL 内,再次收到了来自服务器端的 FIN 报文,说明服务器端由于各种原因没有接收到客户端发出的 ACK 确认报文。客户端再次向服务器端发出 ACK 确认报文,计时器重置,重新开始 2MSL 的计时。
所以,客户端要经历时长为 2MSL 的 TIME-WAIT 阶段;这也是为什么客户端比服务器端晚进入 CLOSED 阶段的原因。
3.如果只有两次握手会发生什么?
服务端可能收到已失效的连接请求报文段,之后傻傻等待,浪费资源。
“已失效的连接请求报文段”产生在这样一种情况下:
客户端发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达服务端。本来这是一个早已失效的报文段,但服务端收到此失效的连接请求报文段后,就误认为是客户端再次发出的一个新的连接请求。于是就向客户端发出确认报文段,同意建立连接。
假设不采用“三次握手”,那么只要服务端发出确认,新的连接就建立了。由于现在客户端并没有发出建立连接的请求,因此不会理睬服务端的确认,也不会向服务发送数据包,而此时服务端在等待客户端给它发送数据,造成资源浪费。
注:超时重传,客户端发送建立连接请求时,若服务端一定时间内没有应答,则会再次发送相同请求,导致已失效的连接请求报文段被服务端接收的情况发生。
4.如果已经建立了连接,但是客户端突然出现故障了怎么办?
TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。
参考资料:https://blog.csdn.net/CC_Together/article/details/105575364