TCP三次握手四次挥手

发布于 2022-04-15  533 次阅读


常用的熟知端口号

应用程序 FTP TFTP TELNET SMTP DNS HTTP SSH MYSQL
熟知端口 21,20 69 23 25 53 80 22 3306
传输层协议 TCP UDP TCP TCP UDP TCP TCP TCP

TCP的概述

TCP把连接作为最基本的对象,每一条TCP连接都有两个端点,这种断点我们叫作套接字(socket),它的定义为端口号拼接到IP地址即构成了套接字,例如,若IP地址为192.3.4.16 而端口号为80,那么得到的套接字为192.3.4.16:80

TCP报文首部

image-20220415161333609

  1. 源端口和目的端口,各占2个字节,分别写入源端口和目的端口;
  2. 序号,占4个字节,TCP连接中传送的字节流中的每个字节都按顺序编号。例如,一段报文的序号字段值是 301 ,而携带的数据共有100字段,显然下一个报文段(如果还有的话)的数据序号应该从401开始;
  3. 确认号,占4个字节,是期望收到对方下一个报文的第一个数据字节的序号。例如,B收到了A发送过来的报文,其序列号字段是501,而数据长度是200字节,这表明B正确的收到了A发送的到序号700为止的数据。因此,B期望收到A的下一个数据序号是701,于是B在发送给A的确认报文段中把确认号置为701;
  4. 数据偏移,占4位,它指出TCP报文的数据距离TCP报文段的起始处有多远;
  5. 保留,占6位,保留今后使用,但目前应都位0;
  6. 紧急URG,当URG=1,表明紧急指针字段有效。告诉系统此报文段中有紧急数据;
  7. 确认ACK,仅当ACK=1时,确认号字段才有效。TCP规定,在连接建立后所有报文的传输都必须把ACK置1;
  8. 推送PSH,当两个应用进程进行交互式通信时,有时在一端的应用进程希望在键入一个命令后立即就能收到对方的响应,这时候就将PSH=1;
  9. 复位RST,当RST=1,表明TCP连接中出现严重差错,必须释放连接,然后再重新建立连接;
  10. 同步SYN,在连接建立时用来同步序号。当SYN=1,ACK=0,表明是连接请求报文,若同意连接,则响应报文中应该使SYN=1,ACK=1;
  11. 终止FIN,用来释放连接。当FIN=1,表明此报文的发送方的数据已经发送完毕,并且要求释放;
  12. 窗口,占2字节,指的是通知接收方,发送本报文你需要有多大的空间来接受;
  13. 检验和,占2字节,校验首部和数据这两部分;
  14. 紧急指针,占2字节,指出本报文段中的紧急数据的字节数;
  15. 选项,长度可变,定义一些其他的可选的参数

TCP连接的建立(三次握手

在这里插入图片描述

最开始的时候客户端和服务器都是处于CLOSED状态。主动打开连接的为客户端,被动打开连接的是服务器。

  1. TCP服务器进程先创建传输控制块TCB,时刻准备接受客户进程的连接请求,此时服务器就进入了LISTEN(监听)状态;
  2. TCP客户进程也是先创建传输控制块TCB,然后向服务器发出连接请求报文,这是报文首部中的同部位SYN=1,同时选择一个初始序列号 seq=x ,此时,TCP客户端进程进入了 SYN-SENT(同步已发送状态)状态。TCP规定,SYN报文段(SYN=1的报文段)不能携带数据,但需要消耗掉一个序号。
  3. TCP服务器收到请求报文后,如果同意连接,则发出确认报文。确认报文中应该 ACK=1,SYN=1,确认号是ack=x+1,同时也要为自己初始化一个序列号 seq=y,此时,TCP服务器进程进入了SYN-RCVD(同步收到)状态。这个报文也不能携带数据,但是同样要消耗一个序号。
  4. TCP客户进程收到确认后,还要向服务器给出确认。确认报文的ACK=1,ack=y+1,自己的序列号seq=x+1,此时,TCP连接建立,客户端进入ESTABLISHED(已建立连接)状态。TCP规定,ACK报文段可以携带数据,但是如果不携带数据则不消耗序号。
  5. 当服务器收到客户端的确认后也进入ESTABLISHED状态,此后双方就可以开始通信了。

使用wireshark抓包,观察TCP三次握手

启用wireshark抓包,访问我自己的服务

curl http://danielw.top

输入过滤条件获取待分析数据包列表ip.addr == 47.118.40.97

image-20220415162041752

图中可以看到wireshark截获到了三次握手的三个数据包。第四个包才是HTTP的, 这说明HTTP的确是使用TCP建立连接的

第一次握手数据包

客户端发送一个TCP,标志位为SYN,序列号为0, 代表客户端请求建立连接。 如下图

image-20220415162510330

数据包的关键属性如下:

  • SYN :标志位,表示请求建立连接
  • Seq = 0 :初始建立连接值为0,数据包的相对序列号从0开始,表示当前还没有发送数据
  • Ack =0:初始建立连接值为0,已经收到包的数量,表示当前没有接收到数据

第二次握手数据包

服务器发回确认包, 标志位为 SYN,ACK. 将确认序号(Acknowledgement Number)设置为客户的I S N加1以.即0+1=1, 如下图

image-20220415163329190

数据包的关键属性如下:

  • [SYN+ACK]: 标志位,同意建立连接,并回送SYN和ACK
  • Seq = 0 :初始建立值为0,表示当前还没有发送数据
  • Ack = 1:表示当前端成功接收的数据位数,虽然客户端没有发送任何有效数据,确认号还是被加1,因为包含SYN或FIN标志位。(并不会对有效数据的计数产生影响,因为含有SYN或FIN标志位的包并不携带有效数据)

第三次握手数据包

客户端再次发送确认包(ACK) SYN标志位为0,ACK标志位为1.并且把服务器发来ACK的序号字段+1,放在确定字段中发送给对方.并且在数据段放写ISN的+1, 如下图:

image-20220415164506779

数据包的关键属性如下:

  • ACK :标志位,表示已经收到记录
  • Seq = 1 :表示当前已经发送1个数据
  • Ack = 1 : 表示当前端成功接收的数据位数,虽然服务端没有发送任何有效数据,确认号还是被加1,因为包含SYN或FIN标志位(并不会对有效数据的计数产生影响,因为含有SYN或FIN标志位的包并不携带有效数据)。
  • 就这样通过了TCP三次握手,建立了连接。开始进行数据交互

TCP连接的释放(四次挥手)

数据传输完毕后,双方都可释放连接。最开始的时候,客户端和服务器都是处于ESTABLISHED状态,然后客户端主动关闭,服务器被动关闭

  • 第一次挥手:
    服务端发送一个 [FIN+ACK] 报文,表示自己没有数据要发送了,想断开连接,并进入 fin_wait_1 状态(不能再发送数据到客户端,但能够发送控制信息 ACK 到客户端)。
  • 第二次挥手:
    客户端收到 [FIN] 报文后,客户端知道不会再有数据从服务端传来,发送 ACK 进行确认,客户端进入 close_wait 状态。此时服务端收到了客户端对 FINACK 后,进入 fin_wait2 状态。
  • 第三次挥手:
    客户端发送 [FIN ACK] 报文给对方,表示自己没有数据要发送了,客户端进入 last_ack 状态。服务端收到了客户端的 FIN 信令后,进入 time_wait 状态,并发送 ACK 确认消息。
  • 第四次挥手:
    服务端在 time_wait 状态下,等待 2MSL(MSL是数据分节在网络中存活的最长时间) 一段时间,没有数据到来的,就认为对面已经收到了自己发送的 ACK 并正确关闭了进入 close 状态,自己也断开了到客户端的 TCP 连接,释放所有资源。当客户端收到服务端的ACK 回应后,会进入 close 状态,并关闭本端的会话接口,释放相应资源

四次挥手

为什么客户端最后还要等待2MSL?

MSL(Maximum Segment Lifetime):报文最大生存时间,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。

2MSL即两倍的MSL,TCP的TIME_WAIT状态也称为2MSL等待状态,当TCP的一端发起主动关闭,在发出最后一个ACK包后就进入了TIME_WAIT状态,必须在此状态上停留两倍的MSL时间,等待2MSL时间主要目的是怕最后一个ACK包对方没收到,那么对方在超时后将重发第三次握手的FIN包,主动关闭端接到重发的FIN包后可以再发一个ACK应答包

对四次挥手进行抓包

image-20220415171255358

第一次挥手数据包

image-20220415170644132

第二次挥手数据包

image-20220415170917621

第三次挥手数据包

image-20220415171037932

第四次挥手数据包

image-20220415171111691

Daniel_WRF
最后更新于 2023-09-22