详解TCP链接的“三次握手”与“四次挥手”(上)

1、TCP connection




客户端与服务器之间数据的发送和返回的过程中须要建立一个叫TCP connection的东西;
因为TCP不存在链接的概念,只存在请求和响应,请求和响应都是数据包,它们之间都是通过由TCP建立的一个从客户端发起,服务器接收的相似链接的通道,这个链接能够一直保持,http请求是在这个链接的基础上发送的;html

在一个TCP链接上是能够发送多个http请求的,不一样的版本这个模式不同。服务器

在HTTP/1.0中这个TCP链接是在http请求建立的时候同步建立的,http请求发送到服务器端,服务器端响应了以后,这个TCP链接就关闭了;
HTTP/1.1中能够以某种方式声明这个链接一直保持,一个请求传输完以后,另外一个请求能够接着传输。这样的好处是:在建立一个TCP链接的过程当中须要“三次握手”的消耗,“三次握手”表明有三次网络传输。
若是TCP链接保持,第二个请求发送就没有这“三次握手”的消耗。HTTP/2中同一个TCP链接里还能够并发地传输http请求。网络

2、TCP报文格式简介



其中比较重要的字段有:并发

(1)序号(sequence number):Seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。tcp

(2)确认号(acknowledgement number):Ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,Ack=Seq+1。工具

(3)标志位(Flags):共6个,即URG、ACK、PSH、RST、SYN、FIN等,具体含义以下:计算机网络

  • URG:紧急指针(urgent pointer)有效。
  • ACK:确认序号有效。
  • PSH:接收方应该尽快将这个报文交给应用层。
  • RST:重置链接。
  • SYN:发起一个新链接。
  • FIN:释放一个链接。

须要注意的是:3d

  • 不要将确认序号Ack与标志位中的ACK搞混了。
  • 确认方Ack=发起方Seq+1,两端配对。

3、TCP的三次握手(Three-Way Handshake)


1.”三次握手”的详解


所谓的三次握手即TCP链接的创建。这个链接必须是一方主动打开,另外一方被动打开的。
如下为客户端主动发起链接的图解:

握手以前主动打开链接的客户端结束CLOSED阶段,被动打开的服务器端也结束CLOSED阶段,并进入LISTEN阶段。随后开始“三次握手”:代理

(1)首先客户端向服务器端发送一段TCP报文,其中:
标记位为SYN,表示“请求创建新链接”;
序号为Seq=X(X通常为1);
随后客户端进入SYN-SENT阶段。指针

(2)服务器端接收到来自客户端的TCP报文以后,结束LISTEN阶段。并返回一段TCP报文,其中:
标志位为SYN和ACK,表示“确认客户端的报文Seq序号有效,服务器能正常接收客户端发送的数据,并赞成建立新链接”(即告诉客户端,服务器收到了你的数据);
序号为Seq=y;
确认号为Ack=x+1,表示收到客户端的序号Seq并将其值加1做为本身确认号Ack的值;随后服务器端进入SYN-RCVD阶段。

(3)客户端接收到来自服务器端的确认收到数据的TCP报文以后,明确了从客户端到服务器的数据传输是正常的,结束SYN-SENT阶段。并返回最后一段TCP报文。其中:
标志位为ACK,表示“确认收到服务器端赞成链接的信号”(即告诉服务器,我知道你收到我发的数据了);
序号为Seq=x+1,表示收到服务器端的确认号Ack,并将其值做为本身的序号值;
确认号为Ack=y+1,表示收到服务器端序号Seq,并将其值加1做为本身的确认号Ack的值;
随后客户端进入ESTABLISHED阶段。

服务器收到来自客户端的“确认收到服务器数据”的TCP报文以后,明确了从服务器到客户端的数据传输是正常的。结束SYN-SENT阶段,进入ESTABLISHED阶段。

在客户端与服务器端传输的TCP报文中,双方的确认号Ack和序号Seq的值,都是在彼此Ack和Seq值的基础上进行计算的,这样作保证了TCP报文传输的连贯性。一旦出现某一方发出的TCP报文丢失,便没法继续"握手",以此确保了"三次握手"的顺利完成。

此后客户端和服务器端进行正常的数据传输。这就是“三次握手”的过程。

2.“三次握手”的动态过程


3.“三次握手”的通俗理解



举个栗子:把客户端比做男孩,服务器比做女孩。用他们的交往来讲明“三次握手”过程:

  • (1)男孩喜欢女孩,因而写了一封信告诉女孩:我爱你,请和我交往吧!;写完信以后,男孩焦急地等待,由于不知道信可否顺利传达给女孩。

  • (2)女孩收到男孩的情书后,心花盛开,原来咱们是两情相悦呀!因而给男孩写了一封回信:我收到你的情书了,也明白了你的心意,其实,我也喜欢你!我愿意和你交往!;
    写完信以后,女孩也焦急地等待,由于不知道回信可否能顺利传达给男孩。

  • (3)男孩收到回信以后很开心,由于发出的情书女孩收到了,而且从回信中知道了女孩喜欢本身,而且愿意和本身交往。而后男孩又写了一封信告诉女孩:你的心意和信我都收到了,谢谢你,还有我爱你!

女孩收到男孩的回信以后,也很开心,由于发出的情书男孩收到了。由此男孩女孩双方都知道了彼此的心意,以后就快乐地交流起来了~~

这就是通俗版的“三次握手”,期间一共往来了三封信也就是“三次握手”,以此确认两个方向上的数据传输通道是否正常。

4.为何要进行第三次握手?


为了防止服务器端开启一些无用的链接增长服务器开销以及防止已失效的链接请求报文段忽然又传送到了服务端,于是产生错误。

因为网络传输是有延时的(要经过网络光纤和各类中间代理服务器),在传输的过程当中,好比客户端发起了SYN=1建立链接的请求(第一次握手)。
若是服务器端就直接建立了这个链接并返回包含SYN、ACK和Seq等内容的数据包给客户端,这个数据包由于网络传输的缘由丢失了,丢失以后客户端就一直没有接收到服务器返回的数据包。
客户端可能设置了一个超时时间,时间到了就关闭了链接建立的请求。再从新发出建立链接的请求,而服务器端是不知道的,若是没有第三次握手告诉服务器端客户端收的到服务器端传输的数据的话,
服务器端是不知道客户端有没有接收到服务器端返回的信息的。

这个过程可理解为:


这样没有给服务器端一个建立仍是关闭链接端口的请求,服务器端的端口就一直开着,等到客户端因超时从新发出请求时,服务器就会从新开启一个端口链接。那么服务器端上没有接收到请求数据的上一个端口就一直开着,久而久之,这样的端口多了,就会形成服务器端开销的严重浪费。

还有一种状况是已经失效的客户端发出的请求信息,因为某种缘由传输到了服务器端,服务器端觉得是客户端发出的有效请求,接收后产生错误。

因此咱们须要“第三次握手”来确认这个过程,让客户端和服务器端可以及时地察觉到由于网络等一些问题致使的链接建立失败,这样服务器端的端口就能够关闭了不用一直等待。

也能够这样理解:“第三次握手”是客户端向服务器端发送数据,这个数据就是要告诉服务器,客户端有没有收到服务器“第二次握手”时传过去的数据。若发送的这个数据是“收到了”的信息,接收后服务器就正常创建TCP链接,不然创建TCP链接失败,服务器关闭链接端口。由此减小服务器开销和接收到失效请求发生的错误。

5.抓包验证


下面是用抓包工具抓到的一些数据包,可用来分析TCP的三次握手:

图中显示的就是完整的TCP链接的”三次握手”过程。在52528 -> 80中,52528是本地(客户端)端口,80是服务器的端口。80端口和52528端口之间的三次来回就是"三次握手"过程。

  • 注意到”第一次握手”客户端发送的TCP报文中以[SYN]做为标志位,而且客户端序号Seq=0;
  • 接下来”第二次握手”服务器返回的TCP报文中以[SYN,ACK]做为标志位;而且服务器端序号Seq=0;确认号Ack=1(“第一次握手”中客户端序号Seq的值+1);
  • 最后”第三次握手”客户端再向服务器端发送的TCP报文中以[ACK]做为标志位;其中客户端序号Seq=1(“第二次握手”中服务器端确认号Ack的值);确认号Ack=1(“第二次握手”中服务器端序号Seq的值+1)。
    这就完成了”三次握手”的过程,符合前面分析的结果。

參考资料:
深刻浅出图解【计算机网络】 之 【TCP可靠传输的实现: 三次握手+滑动窗口】
使用 WireShark 分析 TCP/IP 三次握手 和 四次挥手