TCP三次握手详解及释放链接过程

TCP报文结构

 

  • 源端口和目的端口:各占2个字节,分别写入源端口号和目的端口号。
  • 序号:占4个字节。序号使用mod运算。TCP是面向字节流的,在一个TCP链接中传送的字节流中的每个字节都按顺序编号。故该字段也叫作“报文段序号”。
  • 确认序号:占4个字节,是指望收到对方下一个报文段的第一个数据字节的序号。若确认序号=N,则代表:到序号N-1为止的全部数据都已正确收到。
  • 数据偏移:占4位,表示TCP报文段的首部长度。注意,“数据偏移”的单位是32位字(即以4字节长的字为计算单位)。故TCP首部的最大长度为60字节。
  • 保留:占6位,保留为从此使用,目前置为0;
  • 紧急URG:当URG=1,代表紧急指针字段有效。这时发送方TCP就把紧急数据插入到本报文段数据的最前面,而在紧急数据后面的数据还是普通数据。
  • 确认ACK:当ACK=1时,确认字段才有效。当ACK=0时,确认号无效。TCP规定,在链接创建后全部传送的报文段都必须把ACK置1。
  • 推送PSH:接收方TCP收到PSH=1的报文段,就尽快地交付给接收应用进程,而再也不等到整个缓存都填满了后再向上交付。
  • 复位RST:当RST=1时,代表TCP链接中出现严重差错,必须释放链接,而后再从新创建运输链接。
  • 同步SYN:在链接创建时用来同步序号。当SYN=1而ACK=0时,代表这是一个链接请求报文段。对方若赞成创建链接,则应在响应的报文段中使SYN=1和ACK=1。故SYN置为1,就表示这是一个链接请求和链接接收报文。
  • 终止FIN:用来释放链接。当FIN=1时,代表此报文段的发送方的数据已发送完毕,并要求释放运输链接。
  • 窗口:占2个字节。窗口值做为接收方让发送方设置其发送窗口的依据。
  • 检验和:占2字节。检验和字段检验的范围包括首部和数据这两部分。和UDP数据报同样,在计算检验和时,也要在TCP报文段的前面加上12字节的伪首部。伪首部的格式与UDP用户数据报的伪首部同样,但要将伪首部第四个字段中的17 改成6(协议号),把第5字段中的UDP长度改成TCP长度。
  • 紧急指针:占2字节。紧急指针仅在URG=1时才有意义,它指出本报文段中的紧急数据的字节数。

 

TCP三次握手html

整个流程为:缓存

  1. 客户端主动打开,发送链接请求报文段,将SYN标识位置为1,Sequence Number置为x(TCP规定SYN=1时不能携带数据,x为随机产生的一个值),而后进入SYN_SEND状态
  2. 服务器收到SYN报文段进行确认,将SYN标识位置为1,ACK置为1,Sequence Number置为y,Acknowledgment Number置为x+1,而后进入SYN_RECV状态,这个状态被称为半链接状态
  3. 客户端再进行一次确认,将ACK置为1(此时不用SYN),Sequence Number置为x+1,Acknowledgment Number置为y+1发向服务器,最后客户端与服务器都进入ESTABLISHED状态

 

为何在第3步中客户端还要再进行一次确认呢?服务器

这主要是为了防止已经失效的链接请求报文段忽然又传回到服务端而产生错误的场景:所谓"已失效的链接请求报文段"是这样产生的。正常来讲,客户端发出链接请求,但由于链接请求报文丢失而未收到确认。因而客户端再次发出一次链接请求,后来收到了确认,创建了链接。数据传输完毕后,释放了链接,客户端一共发送了两个链接请求报文段,其中第一个丢失,第二个到达了服务端,没有"已失效的链接请求报文段"。网络

如今假定一种异常状况,即客户端发出的第一个链接请求报文段并无丢失,只是在某些网络节点长时间滞留了,以致于延误到链接释放之后的某个时间点才到达服务端。原本这个链接请求已经失效了,可是服务端收到此失效的链接请求报文段后,就误认为这是客户端又发出了一次新的链接请求。因而服务端又向客户端发出请求报文段,赞成创建链接。假定不采用三次握手,那么只要服务端发出确认,链接就创建了。post

因为如今客户端并无发出链接创建的请求,所以不会理会服务端的确认,也不会向服务端发送数据,可是服务端却觉得新的传输链接已经创建了,并一直等待客户端发来数据,这样服务端的许多资源就这样白白浪费了。spa

采用三次握手的办法能够防止上述现象的发生。好比在上述的场景下,客户端不向服务端的发出确认请求,服务端因为收不到确认,就知道客户端并无要求创建链接。3d

 

 

TCP四次挥手指针

TCP三次握手是TCP链接创建的过程,TCP四次挥手则是TCP链接释放的过程下面是TCP四次挥手的流程图:htm

 

当客户端没有数据再须要发送给服务端时,就须要释放客户端的链接,这整个过程为:blog

  1. 客户端发送一个报文给服务端(没有数据),其中FIN设置为1,Sequence Number置为u,客户端进入FIN_WAIT_1状态
  2. 服务端收到来自客户端的请求,发送一个ACK给客户端,Acknowledge置为u+1,同时发送Sequence Number为v,服务端年进入CLOSE_WAIT状态
  3. 服务端发送一个FIN给客户端,ACK置为1,Sequence置为w,Acknowledge置为u+1,用来关闭服务端到客户端的数据传送,服务端进入LAST_ACK状态
  4. 客户端收到FIN后,进入TIME_WAIT状态,接着发送一个ACK给服务端,Acknowledge置为w+1,Sequence Number置为u+1,最后客户端和服务端都进入CLOSED状态

 

 

为何建连接要3次握手,断连接须要4次挥手?

  • 对于建连接的3次握手,主要是要初始化Sequence Number 的初始值。通讯的双方要互相通知对方本身的初始化的Sequence Number(缩写为ISN:Inital Sequence Number)——因此叫SYN,全称Synchronize Sequence Numbers。也就上图中的 x 和 y。这个号要做为之后的数据通讯的序号,以保证应用层接收到的数据不会由于网络上的传输的问题而乱序(TCP会用这个序号来拼接数据)。
  • 对于4次挥手,其实你仔细看是2次,由于TCP是全双工的,因此,发送方和接收方都须要Fin和Ack。只不过,有一方是被动的,因此看上去就成了所谓的4次挥手。若是两边同时断链接,那就会就进入到CLOSING状态,而后到达TIME_WAIT状态。下图是双方同时断链接的示意图(你一样能够对照着TCP状态机看):

 

使用Wireshark抓包验证TCP三次握手过程

为了加深对TCP三次握手的理解,抓包看一下TCP三次握手的过程。

抓包下来的内容为:

这里多说一句,因为wireshark抓包针对的是网卡,所以只要某张网卡上有网络访问,就会有数据包,这会致使Wireshark的抓包结果里面会有大量数据包,而大多数都不是想要的,这种状况可使用Wireshark的过滤规则。我这里因为知道目标ip,所以使用的是"ip.src == xxx.xxx.xxx.xxx or ip.dst == xxx.xxx.xxx.xxx"这条规则只过滤特定的ip。

从抓包结果看来,整个过程符合TCP三次握手的预期:

  1. 客户端发送SYN给服务端
  2. 服务端返回SYN+ACK给客户端
  3. 客户端确认,返回ACK给服务端

至于Sequence Number和Acknowledge Number就不看了,可是注意,前面说了Sequence Number是随机产生的一个值,可是这里确是0,不光这里是0,抓其余的任何包这个值都是0。但其实这里并非真的0,而是Wireshark为了显示更好阅读,使用了relative sequence number相对序号,Sequence Number具体值咱们也是能够看到的:

第一个红框就是上面说的relative sequence number,第二个红框就是Sequence Number的真实值0xc978aa7e,转换为十进制为3380128382,就是随机产生的Sequence Number。

顺便能看到,下一个数据包就是HTTP的数据包,由于TCP三次握手已完成,链接创建,正式传输应用层数据,传输的HTTP内容大小为704字节。

 

TCP 三次握手原理,你真的理解吗?