TCP三次握手四次挥手,看这一篇就够了

前言

最近有粉丝私信说,计算机网络中的三次握手和四次挥手好难,怎么都搞不懂,面试频率还很高。真的有这么难吗?小A也是查漏补缺,今天带大家一起来盘一下这个神奇的TCP连接。

TCP连接和断开

TCP传输控制协议是面向连接的可靠的传输层协议,在进行数据传输之前,需要在传输数据的两端(客户端和服务器端)创建一个连接,这个连接由一对插口地址唯一标识,即是在IP报文首部的源IP地址、目的IP地址,以及TCP数据报首部的源端口地址和目的端口地址。TCP首部结构如下

TCP三次握手四次挥手,看这一篇就够了_第1张图片

通常情况下,一个正常的TCP连接,都会有三个阶段:

  • TCP三次握手;

  • 数据传送;

  • TCP四次挥手

其中在TCP连接和断开连接过程中的关键部分如下:

  • 源端口号:即发送方的端口号,在TCP连接过程中,对于客户端,端口号往往由内核分配,无需进程指定;

  • 目的端口号:即发送目的的端口号;

  • 序号:即为发送的数据段首个字节的序号;

  • 确认号:在收到对方发来的数据报,发送确认时期待对方下一次发送的数据序号;

  • SYN:同步序列编号,Synchronize Sequence Numbers;

  • ACK:确认编号,Acknowledgement Number;

  • FIN:结束标志,FINish

抓包分析

  1. 打开tcpdump
  sudo  tcpdump -n  -S -i en0 host www.baidu.com
  1. 另起一个终端
  curl http://www.baidu.com
  1. 输出如下
### 三次握手开始
18:43:14.096580 IP 192.168.1.102.54637 > 39.156.66.18.80: Flags [S], seq 2648989976, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 1251699469 ecr 0,sackOK,eol], length 0
18:43:14.116228 IP 39.156.66.18.80 > 192.168.1.102.54637: Flags [S.], seq 1206993270, ack 2648989977, win 8192, options [mss 1452,nop,wscale 5,nop,nop,nop,nop,nop,nop,nop,nop,nop,nop,nop,nop,sackOK,eol], length 0
18:43:14.116310 IP 192.168.1.102.54637 > 39.156.66.18.80: Flags [.], ack 1206993271, win 4096, length 0
### 三次握手接收

### 数据传输开始
18:43:14.116358 IP 192.168.1.102.54637 > 39.156.66.18.80: Flags [P.], seq 2648989977:2648990054, ack 1206993271, win 4096, length 77: HTTP: GET / HTTP/1.1
18:43:14.125715 IP 39.156.66.18.80 > 192.168.1.102.54637: Flags [.], ack 2648990054, win 916, length 0
18:43:14.126943 IP 39.156.66.18.80 > 192.168.1.102.54637: Flags [.], seq 1206993271:1206994723, ack 2648990054, win 916, length 1452: HTTP: HTTP/1.1 200 OK
18:43:14.127525 IP 39.156.66.18.80 > 192.168.1.102.54637: Flags [P.], seq 1206994723:1206996052, ack 2648990054, win 916, length 1329: HTTP
18:43:14.127587 IP 192.168.1.102.54637 > 39.156.66.18.80: Flags [.], ack 1206996052, win 4075, length 0
### 数据传输结束

### 四次挥手开始
18:43:14.127870 IP 192.168.1.102.54637 > 39.156.66.18.80: Flags [F.], seq 2648990054, ack 1206996052, win 4096, length 0
18:43:14.138218 IP 39.156.66.18.80 > 192.168.1.102.54637: Flags [.], ack 2648990055, win 916, length 0
18:43:14.138226 IP 39.156.66.18.80 > 192.168.1.102.54637: Flags [F.], seq 1206996052, ack 2648990055, win 916, length 0
18:43:14.138359 IP 192.168.1.102.54637 > 39.156.66.18.80: Flags [.], ack 1206996053, win 4096, length 0
18:43:17.146466 IP 39.156.66.18.80 > 192.168.1.102.54637: Flags [R], seq 1206996053, win 0, length 0
### 四次挥手结束

报文数据含义

  • 18:43:14.127870 时间戳

  • IP 网络协议名称

  • 192.168.1.102.54637 > 39.156.66.18.80: 报文发送方和接收方地址和端口

  • Flags [F.], 标志位 取值有[S.][.][P.][F.]

  • seq 2648990054, 请求同步序列号

  • ack 1206996052, 已经同步的序列号

  • win 4096, 当前窗口可用大小

  • length 0 TCP报文体长度

TCP三次握手阶段

TCP三次握手四次挥手,看这一篇就够了_第2张图片
  1. 由主机A向主机B发起TCP连接请求。主机A发送:同步序列编号SYN置为1,发送序号seq为一个随机数,这里假设为x,确认序号ack置为0;

  2. 主机B收到连接请求。主机B响应:标志位 SYN置为1ACK置为1.并将确认序号ack置为x+1,然后生成一个随机y作为发送序号seq(因为所确认的数据报的确认序号未初始化);

  3. 主机A对接收到的确认进行确认。发送:标志位ACK置为1 ,将确认序号ack置为y + 1,然后将发送序号seq置为x+1(即为接收到的数据报的确认序号)

常见问题

为什么是三次握手而不是两次?

假设两次握手,主机A向主机B发送一个连接请求数据报,由于这个数据报在网络中滞留导致其迟到了,这时服务器仍然会接收并发回一个确认数据报。但是A却因为没有在规定时间内收到B的确认而将发送的请求连接置为无效。一段时间后,A接到B发送过来的确认,A认为自己现在没有发送与B的连接,但是B则认为自己连接成功了,于是一直在等待A的消息,就像单相思一样,久久得不到回应。这会导致资源的浪费,因此,两次握手是不行的,必须三次握手,即对B发过来的确认再进行一次确认,从而建立可靠连接。

四次挥手

连接双方在完成数据传输之后就需要断开连接。由于TCP连接是属于全双工的,即连接双方可以在一条TCP连接上互相传输数据,因此在断开时存在一个半关闭状态,即有有一方失去发送数据的能力,却还能接收数据。因此,断开连接需要分为四次。主要过程如下:

TCP三次握手四次挥手,看这一篇就够了_第3张图片
  1. 主机A向主机B发起断开连接请求,之后主机A进入FIN-WAIT-1状态;

  2. 主机B收到主机A的请求后,向主机A发回确认,然后进入CLOSE-WAIT状态;

  3. 主机A收到B的确认之后,进入FIN-WAIT-2状态,此时便是半关闭状态,即主机A失去发送能力,但是主机B却还能向A发送数据,并且A可以接收数据。此时主机B占主导位置了,如果需要继续关闭则需要主机B来操作了;

  4. 主机B向A发出断开连接请求,然后进入LAST-ACK状态;

  5. 主机A接收到请求后发送确认,进入TIME-WAIT状态,等待2MSL之后进入CLOSED状态,而主机B则在接受到确认后进入CLOSED状态;

  • TIME_WAIT
    主动要求关闭的机器表示收到了对方的FIN报文,并发出了ACK报文,进入TIME_WAIT状态,等2MSL后即可进入CLOSED状态。如果在FIM_WAIT_1状态下,同时收到带有FIN和ACK标志的报文时,可直接进入TIME_WAIT状态。
  • CLOSE-WAIT
    被动要求关闭的机器收到对方请求关闭连接的FIN报文,在第一次ACK应答后,进入CLOSE-WAIT状态。这个状态表示等待关闭,并通知应用程序发送剩余数据,处理现场信息,关闭相关资源。

常见问题

为何主机A在发送了最后的确认后没有进入CLOSED状态,反而进入了一个等待2MSL的TIME-WAIT?

原因有以下几点:

第一,确保主机B能够顺利进入ClOSED状态。如果处于LAST-ACK状态的主机B一直收不到来自主机A的确认,它会重传断开连接请求,然后主机A就可以有足够的时间去再次发送确认。但是这也只能尽最大力量来确保能够正常断开,如果主机A的确认总是在网络中滞留失效,从而超过了2MSL,最后也无法正常断开;

第二,防止失效请求。如果主机A在发送了确认之后立即进入CLOSED状态。假设之后主机A再次向主机B发送一条连接请求,而这条连接请求比之前的确认报文更早地到达主机B,则会使得主机B以为这条连接请求是在旧的连接中A发出的报文,并不看成是一条新的连接请求了,即使得这个连接请求失效了,增加2MSL的时间可以使得这个失效的连接请求报文作废,这样才不影响下次新的连接请求中出现失效的连接请求。

为什么断开连接请求报文只有三个,而不是四个?

​ 因为在TCP连接过程中,确认的发送有一个延时(即经受延时的确认),一端在发送确认的时候将等待一段时间,如果自己在这段事件内也有数据要发送,就跟确认一起发送,如果没有,则确认单独发送。而我们的抓包实验中,由服务器端先断开连接,之后客户端在确认的延迟时间内,也有请求断开连接需要发送,于是就与上次确认一起发送,因此就只有三个数据报了。

关注不迷路

欢迎关注公众号【程序员Alex】

你可能感兴趣的:(TCP三次握手四次挥手,看这一篇就够了)