浅谈TCP的三次握手与四次分手

浅谈TCP的三次握手与四次分手


  TCP是面向连接的,无论哪一方向另一方发送数据之前,都必须先在双方之间建立一条连接。TCP协议是运输层协议的一种,提供可靠的数据传输服务,TCP连接时全双工通信,这意味通信的双方都可以同时发送和接收数据,连接是通过三次握手进行初始化的。三次握手的目的是同步连接双方的序列号和确认号并交换TCP窗口大小信息。
注意TCP三次握手过程是没有数据传送的,那是建立连接的特殊数字节点流,但是TCP四次分手过程是有数据传送的


  • TCP包头
    在这里插入图片描述
      上图是TCP协议头部的格式,这是理解下面三次握手四次分手的核心
    • 源端口跟目的端口: 二者分别占用16位,他们可以区别主机中不同的进程,而IP协议是用来区分不同的主机,源端口号和目的端口号配合上IP首部中的源IP地址和目的IP地址就能唯一的确定一个TCP连接,这就是为啥称为TCP/IP协议了,二者是密不可分的。
    • 序列号 seq 用来标识从TCP发端向TCP收端发送的数据字节流,它表示在这个报文段中的的第一个数据字节在数据流中的序号;主要用来解决网络报乱序的问题。
    • 确认号 ACK 表示接收方期望收到发送方下一个报文段的第一个字节数据的编号。因此,确认序号应当是上次已成功收到数据字节序号加1 ack=x+1 。不过,只有当标志位中的 ACK 标志(下面介绍)为1时该确认序列号的字段才有效。主要用来解决不丢包的问题;
    • 控制位: URG ACK PSH RST SYN FIN,共6个,每一个标志位表示一个控制功能。
      • URG: 当URG=1,表明紧急指针字段有效。告诉系统此报文段中有紧急数据*
      • ACK:此标志表示前面应答确认号字段是否有效,就是说前面所说的TCP应答确认号将会包含在TCP数据包中;有两个取值:0和1,为1的时候表示应答号文有效,反之为0,只有当ACK=1时,前面的确认号字段才生效。TCP规定连接建立后,ACK必须为1,带ack标志的TCP报文段被称为确认报文段。
      • PSH:提示接收端应用程序应该立即从TCP接收缓冲区中读走数据,为接收后续数据腾出空间。如果为1,则表示对方应当立即把数据提交给上层应用,而不是缓存起来,如果应用程序不将接收到的数据读走,就会一直停留在TCP接收缓冲区中排队
      • RST:如果收到一个RST=1的报文,说明与主机的连接出现了严重错误(如主机崩溃),必须释放连接,然后再重新建立连接。或者说明上次发送给主机的数据有问题,主机拒绝响应,带RST标志的TCP报文段称为复位报文段
      • SYN:表示同步序号,用来建立连接。SYN标志位和ACK标志位搭配使用。
        • SYN=1,ACK=0 ,表示这是一个请求建立连接的报文段
        • SYN=1,ACK=1 时,表示对方同意建立连接。
        • SYN=1 时,说明这是一个请求建立连接或者同意建立连接的报文,只有在前两次握手中 SYN=1 时,带SYN标志的TCP报文段才可以称为同步报文段
      • FIN:表示通知对方本端要关闭连接了,标记数据是否发送完毕。如果FIN=1,即告诉对方:“我的数据已经发送完毕,你可以释放连接了”,带FIN标志的TCP报文段称为结束报文段
      • 窗口大小:表示现在允许对方发送的数据量,也就是告诉对方,从本报文段
        的确认号开始允许对方发送的数据量,达到此值,需要ACK确认后才能再继续传送后面数据,由Window size value * Window size scaling factor(此值在三次握手阶段TCP选项Window scale协商得到)得出此值

注意很重要的两点,可以有助于下面知识点的理解:

  • 1.ACK报文是用来确认应答的,SYN报文是用来同步的。
  • 2.确认序号ACK跟控制标志位里面的ack不是一个东西,二者不要搞混,只有ACK=1时,ack才有意义。

三次握手是什么

  三次握手(Three-way Handshake)其实就是指建立一个TCP连接时,需要客户端和服务器总共发送3个包。进行三次握手的主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备。实质上其实就是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号,交换TCP窗口大小信息。
在这里插入图片描述

  • 1.第一次握手:建立连接,客户端给服务器端发送一个自己的SYN报文,将SYN的位置变成 SYN=1,seq=x,然后客户端进入 SYN_SEND 状态,等待服务器的确认.
      首部的同步位SYN=1,初始序号seq=x,SYN=1的报文段不能携带数据,但是要消耗掉一个序号
  • 2.第二次握手:服务端收到SYN报文段后,必须确认客户端的SYN报文,然后以自己的SYN=1作为应答,并且给出自己的初始序列号seq=y,同时发送一个ack=x+1的确认号,表示自己已经收到了客户端的SYN,此时服务器处于 SYN_RECVD 状态。
      在确认报文段中 SYN=1 ACK=1,确认号段ack=x+1,初始序号seq=y
  • 3.第三次握手:客户端收到服务端的报文段 “SYN+ACK包” 后,然后向服务端发送确认报文即“ACK包”,并附带确认报文ack=y+1,内容为seq=x+1表示已经收到服务器发送的报文,此时客户端状态为 ESTAB-LISHED.服务器收到ACK报文后,也处于 ESTAB-LISHED 状态,此时开始彼此建立连接。
      确认报文段ACK=1 确认号ack=y+1(y代表服务端的字段号,+1代表已经收到,需要y的下一段即+1),序列号seq=x+1(注意,序列号是客户端自己的序列号,第初始第一是x,所以这次即第二次报文段是x+1)。

握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。理想状态下,TCP连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP 连接都将被一直保持下去。


  • 为什么需要三次握手,两次不行吗?四次呢?
    首先来看下三次握手的目的:
    • 第一次握手:客户端发送网络包,服务端收到了。
      这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。
    • 第二次握手:服务端发包,客户端收到了。
      这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常。
    • 第三次握手:客户端发包,服务端收到了。
      这样服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常。

  因此,需要用三次握手才能确认双方的接受以及发送能力是否正常。

  • 如果用两次握手,则会出现下面的状况:

  如客户端发出连接请求,但因连接请求报文丢失而未收到确认,于是客户端再重传一次连接请求。后来收到了确认,建立了连接。数据传输完毕后,就释放了连接,客户端共发出了两个连接请求报文段,其中第一个丢失,第二个到达了服务端,但是第一个丢失的报文段只是在某些网络结点长时间滞留了,延误到连接释放以后的某个时间才到达服务端,此时服务端误认为客户端又发出一次新的连接请求,于是就向客户端发出确认报文段,同意建立连接,不采用三次握手,只要服务端发出确认,就建立新的连接了,此时客户端忽略服务端发来的确认报文,也不发送数据,则服务端会一直等待客户端发送数据,浪费服务端的资源

  • 如果用四次握手,本来三次已经建立通信连接,再来一次就是资源的浪费。

四次挥手

  客户端和服务器通过三次握手建立了TCP连接以后,当数据传送完毕,肯定是要断开TCP连接的啊。那对于TCP的断开连接,这里就有了神秘的“四次分手”。
在这里插入图片描述
  建立一个连接需要三次握手,而终止一个连接要经过四次挥手(也有将四次挥手叫做四次握手的)。这由TCP的半关闭(half-close)造成的。所谓的半关闭,其实就是TCP提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力。
  TCP 的连接的拆除需要发送四个包,因此称为四次挥手(Four-way handshake),客户端或服务器均可主动发起挥手动作。
  刚开始双方都处于 ESTABLISHED 状态,假如是客户端先发起关闭请求。
四次挥手的过程如下:

  • 1. 第一次挥手:客户端发送一个FIN报文,用来关闭客户端到服务器的数据传送,也就是客户端告诉服务器:我已经不会再给你发数据了(当然,在FIN包之前发送出去的数据,如果没有收到对应的ack确认报文,客户端依然会重发这些数据),但是,此时客户端还可以接受数据,此时客户端处于FIN-WAIT1状态。
    • 即客户端发请求释放报文段 “FIN1=1,序列号seq=u”,并停止再发送数据,主动关闭TCP连接,进入FIN-WAIT1(终止等待1)状态,等待服务端的确认。
  • 2.第二次挥手: 服务端收到客户端发送的 FIN 后,会发送ACK确认报文,并带上确认号ack=u+1.表示已经收到客户端发送的报文了,此时服务端处于 CLOSE-WAIT状态。
       确认报文段即 “ACK=1,确认号ack=u+1,服务端的序列号seq=v” ,此时服务端就进入了CLOSE-WAIT(关闭等待)状态,是TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了。这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据客户端依然要接受,此时进入客户端进入FIN_WAIT2(终止等待2)状态,等待服务端发出最后的数据。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。
  • 3.第三次挥手: 服务端发送一个FIN报文,用来关闭服务端到客户端的数据传送,也就是告诉客户端,我的数据也传送完了,不会继续给你发送数据了。由于此时处于半关闭状态,数据依然传送了一部分,这个时候服务端处于 LAST-ACK(最后确认) 状态,等待客户端的确认
      服务端发出的报文段为: FIN=1,确认报文ACK=1.确认号ack=u+1(表示服务端收到客户端的数据了,需要下一个数据+1),服务端自己的序列号seq=w, 然后服务端进入 LAST-ACK 状态。
  • 4.第四次挥手: 客户端收到服务端发送的FIN报文后,要发送一个确认ACK报文给服务端做为应答,此时客户端处于TIME-WAIT状态,注意此时TCP连接还没有断开,必须经过 2*MSL(最长报文段寿命) 的时间后,确认后续数据的传送并且服务端没有回复的报文后,说明服务端的状态已经是 CLOSED 状态,这时候客户端就可以关闭进入 CLOSED 状态了。
       客户端收到服务端的报文后,回复 确认报文段:ACK=1,确认号ack=w+1,自己的序列号seq=u+1(第一次挥手发送序列号是u),注意此时不需要 FIN 报文。

  • 为什么客户端最后还要等待2MSL?
      MSL(Maximum Segment Lifetime),TCP允许不同的实现可以设置不同的MSL值。对一个具体实现所给定的MSL值,处理的原则是:当TCP执行一个主动关闭,并发回最后一个ACK,该连接必须在TIME_WAIT状态停留的时间为2倍的MSL。这样可让TCP再次发送最后的ACK以防这个ACK丢失(另一端超时并重发最后的FIN)

      第一,保证客户端发送的最后一个ACK报文能够到达服务器,因为这个ACK报文可能丢失,站在服务器的角度看来,我已经发送了FIN+ACK报文请求断开了,客户端还没有给我回应,应该是我发送的请求断开报文它没有收到,于是服务器又会重新发送一次,而客户端就能在这个2MSL时间段内收到这个重传的报文,接着给出回应报文,并且会重启2MSL计时器。
      第二,防止类似与“三次握手”中提到了的“已经失效的连接请求报文段”出现在本连接中。客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样新的连接中不会出现旧连接的请求报文。


为什么建立连接是三次握手,关闭连接确是四次挥手呢
  建立连接的时候,服务端处于LISTEN状态下,收到建立连接请求的SYN报文后,把ACK跟SYN放在一个报文里传给客户端。
  而关闭连接时,服务端收到对方的FIN 报文后,仅仅表示客户端不再发送数据了但是数据传送依然没有关闭,而自己也未必能全部数据都发送给客户端了,所以进入CLOSE-WAIT状态,继续传送数据发送确认请求收到报文,然后再一次发送FIN报文给客户端同意关闭连接,客户端为了数据的完整性,必须等 2*MSL时间后,才会进入CLOSE状态关闭连接。
   所以ACK报文 跟FIN报文是分开传送,所以就多了一次挥手动作。


区分主动断开和被动端口方的端口状态:

  • 主动端口方:SYN_SENT、FIN_WAIT1、FIN_WAIT2、CLOSING、TIME_WAIT 。
  • 被动断开方:LISTEN、SYN_RCVD、CLOSE_WAIT、LAST_ACK 。
  • 都具有的:CLOSED 、ESTABLISHED 。
    在这里插入图片描述

完 毕

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值