TCP状态转化总结

文章转载自:TCP的三次握手和四次挥手

TCP连接建立过程——三次握手

  • 第一次握手:客户端发送位码为 SYN = 1(SYN 标志位置位),随机产生初始序列号 Seq = J 的数据包到服务器。服务器由 SYN = 1(置位)知道,客户端要求建立联机。
  • 第二次握手:服务器收到请求后要确认联机信息,向客户端发送确认号Ack = (客户端的Seq +1,J+1),SYN = 1,ACK = 1(SYN,ACK 标志位置位),随机产生的序列号 Seq = K 的数据包。
  • 第三次握手:客户端收到后检查 Ack 是否正确,即第一次发送的 Seq +1(J+1),以及位码ACK是否为1。若正确,客户端会再发送 Ack = (服务器端的Seq+1,K+1),ACK = 1,以及序号Seq为服务器确认号J 的确认包。服务器收到后确认之前发送的 Seq(K+1) 值与 ACK= 1 (ACK置位)则连接建立成功。

经过了这三步之后,客户端与服务器端就成功建立起一个 TCP连接。这三个步骤统称为三次握手。

(上面Seq表示序列号,Ack表示确认号,SYN和ACK以及FIN等都是标志位。ACK 被设置为 1表示确认号字段是有效的,如果 ACK为 0,则该段不包含确认信息。SYN 被用于建立连接过程,在连接请求中,SYN = 1 和 ACK = 0 表示该段没有捎带确认字段。连接应答会捎带一个确认,所以应答时会有 SYN= 1 和 ACK= 1。另外发送ACK无需任何代价,所以我们会看到一旦一个连接建立起来,ACK标志总是被置为1)

从上图可以看出,当客户端调用connect 时,触发了连接请求,向服务器发送了 SYN J包,这时 connect 进入阻塞状态;服务器监听到连接请求,即收到 SYN J包,调用 accept函数接收请求向客户端发送 SYN K,ACK J+1,这时 accept 进入阻塞状态,客户端收到服务器的 SYN K,ACK J+1之后,这时 connect 返回,并对 SYN K 进行确认,服务器收到 ACK K+1时,accept返回,至此三次握手完毕,连接建立。可以得知:客户端的 connect在三次握手的第二次返回,而服务器端的 accept在三次握手的第三次返回。

为什么是三次握手:

有讲到“三次握手”的目的是“为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误”。
这样说明“已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。”

下面用抓包工具 Wireshark 实际分析下三次握手的过程,这里是登陆一个网址,然后Wireshark 过滤http 找到与浏览器打开该网站相关的数据包。

连接的是 HTTP 服务器,可以看到其端口号正是80,客户端的端口号则是随机的。红色框框标记的则是三次握手过程,下面具体来看

第一次握手数据包:

客户端发送一个TCP,标志位SYN置位,序列号为4225926656(默认是相对序列号,可以在Wireshark中protocol preference 设置Absolute Number,显示真正的序列号)。表示客户端请求建立连接。

第二次握手数据包:

看源端口和目的端口。服务器发回确认包,标志位SYN和ACK置位,将确认序号Ack设置为客户的ISN(初始序号)+1,为4225926657,同时发送序列号为3022381253。

第三次握手数据包

客户端再次发送确认包,其中ACK置位,确认序号Ack设置为服务器发过来的序号Seq+1,为3022381254,并发送序号=服务器发过来的确认号。

对于建连接的三次握手,主要是初始化Seq的值。通信的双方要互相通知对方自己的初始化的Seq(ISN),这个号(上面的K,J)作为以后的数据通信的序号,以保证应用层接收到的数据不会因为网络上的传输问题而乱序,TCP会用这个序号来拼接数据。

TCP连接终止过程——四次挥手

由于TCP连接是全双工的,因此每个方向都必须单独进行关闭,也就是发送方和接收方都需要Fin和Ack。这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接,收到一个FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。

这里我们假定客户端主动关闭(实际上谁先执行主动关闭没本质区别,通话结束了,谁先挂断没啥区别)

客户端发送一个FIN Seq = M(FIN置位,序号为M)包,用来关闭客户端到服务器端的数据传送。
服务器端收到这个FIN,它发回一个ACK,确认序号Ack 为收到的序号M+1。
服务器端关闭与客户端的连接,发送一个FIN Seq = N 给客户端。
客户端发回ACK 报文确认,确认序号Ack 为收到的序号N+1。

对于四次挥手,其实仔细看是两次,因为TCP是全双工的,必须双方都关闭才可以,单方会有两次,共有四次。终止的时候,有一方是被动的,所以看上去就成了四次挥手。

前面有说道,一旦连接建立起来,ACK标志位总是被置为1。所以我们在下图可以看到TCP建立连接之后,ACK总是被置为1的。

关闭连接过程主要看FIN标志位是否置位,ACK在连接建立成功之后都是置为1的。

上面Wireshark抓包是服务器端先执行主动关闭。

第一次挥手:服务器端发起主动关闭,FIN置位,Seq = 3022381791;

第二次挥手:客户端收到FIN后,发回ACK,Ack = Seq + 1 = 3022381792;至此服务器端的连接关闭了,接下来还需要关闭客户端的。

第三次挥手:客户端发送FIN,Seq = 4225929031;

第四次挥手:服务器端收到FIN后,发回ACK,Ack = Seq + 1 = 4225929032.这样客户端的连接也关闭了。至此全双工的TCP连接关闭。

另外通过下面的截图可以发现:数据传输中的 Sequence Number 的增加是和传输字节数相关的。

文章目录
  1. 1. TCP连接建立过程——三次握手
  2. 2. 为什么是三次握手:
    1. 2.1. 第一次握手数据包:
    2. 2.2. 第二次握手数据包:
    3. 2.3. 第三次握手数据包
  3. 3. TCP连接终止过程——四次挥手
|