转载声明
一、TCP 是什么?
TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。
我们知道了上述了解到了 TCP 的定义,通俗一点的讲,TCP 就是一个双方通信的一个规范标准(协议)。
我们在学习 TCP 握手过程之前,首先必须了解 TCP 报文头部的一些标志信息,因为在 TCP 握手的过程中,会使用到这些报文信息,如果没有掌握这些信息,在学习握手过程中,整个人处于懵逼状态,也是为了能够深入 TCP 三次握手的原理。
二、TCP 头部报文
2.1 source port 和 destination port
两者分别为「源端口号」和「目的端口号」。源端口号就是指本地端口,目的端口就是远程端口。
一个数据包(pocket)被解封装成数据段(segment)后就会涉及到连接上层协议的端口问题。
可以这么理解,我们可以想象发送方很多的窗户,接收方也有很多的窗户,这些窗口都标有不同的端口号,源端口号和目的端口号就分别代表从哪个规定的串口发送到对方接收的窗口。不同的应用程度都有着不同的端口,之前网络分层的文章中有提到过。
扩展:应用程序的端口号和应用程序所在主机的 IP 地址统称为 socket(套接字),IP:端口号, 在互联网上 socket 唯一标识每一个应用程序,源端口+源IP+目的端口+目的IP称为”套接字对“,一对套接字就是一个连接,一个客户端与服务器之间的连接。
2.2 Sequence Numbe
称为「序列号」。用于 TCP 通信过程中某一传输方向上字节流的每个字节的编号,为了确保数据通信的有序性,避免网络中乱序的问题。接收端根据这个编号进行确认,保证分割的数据段在原始数据包的位置。
再通俗一点的讲,每个字段在传送中用序列号来标记自己位置的,而这个字段就是用来完成双方传输中确保字段原始位置是按照传输顺序的。(发送方是数据是怎样一个顺序,到了接受方也要确保是这个顺序)
PS:初始序列号由自己定,而后绪的序列号由对端的 ACK 决定:SN_x = ACK_y (x 的序列号 = y 发给 x 的 ACK),这里后边会讲到。
2.3 Acknowledgment Numbe
称为「确认序列号」。确认序列号是接收确认端所期望收到的下一序列号。确认序号应当是上次已成功收到数据字节序号加1,只有当标志位中的 ACK 标志为 1 时该确认序列号的字段才有效。主要用来解决不丢包的问题。
若确认号=N,则表明:到序号N-1为止的所有数据都已正确收到。
在这里,现在我们只需知道它的作用是什么,就是在数据传输的时候是一段一段的,都是由序列号进行标识的,所以说,接收端每接收一段,之后就想要的下一段的序列号就称为「确认序列号」。
说明:ack值相同的多个段,表示是对同一个请求的响应数据的多个segment。只是这个数据被分割成了多个segment。换而言之,如果多个包的ack值相同,那么这些包是同一个数据分割成的多个segment。
2.4 TCP Flag
TCP
首部中有 6 个标志比特,它们中的多个可同时被设置为 1
,主要是用于操控 TCP
的状态机的,依次为URG,ACK,PSH,RST,SYN,FIN
。
不要求初学者全部掌握,在这里只讲三个重点的标志:
2.4.1 ACK
这个标识可以理解为发送端发送数据到接收端,发送的时候 ACK 为 0,标识接收端还未应答,一旦接收端接收数据之后,就将 ACK 置为 1,发送端接收到之后,就知道了接收端已经接收了数据。
此标志表示「应答域有效」,就是说前面所说的TCP应答号将会包含在 TCP 数据包中;有两个取值:0 和 1,为 1 的时候表示应答域有效,反之为 0;
2.4.2 SYN
表示「同步序列号」,是 TCP 握手的发送的第一个数据包。
用来建立 TCP 的连接。SYN 标志位和 ACK 标志位搭配使用,当连接请求的时候SYN=1,ACK=0,连接被响应的时候SYN=1,ACK=1;这个标志的数据包经常被用来进行端口扫描。扫描者发送一个只有 SYN 的数据包,如果对方主机响应了一个数据包回来 ,就表明这台主机存在这个端口。看下面动画:
2.4.3 FIN
表示发送端已经达到数据末尾,也就是说双方的数据传送完成,没有数据可以传送了,发送FIN标志位的 TCP 数据包后,连接将被断开。这个标志的数据包也经常被用于进行端口扫描。
这个很好理解,就是说,发送端只剩最后的一段数据了,同时要告诉接收端后边没有数据可以接受了,所以用FIN标识一下,接收端看到这个FIN之后,哦!这是接受的最后的数据,接受完就关闭了。动画如下:
其他
2.5 Window size
称为滑动窗口大小。所说的滑动窗口,用来进行流量控制。
三、为什么进行 TCP 三次握手?
第一,为了确认双方的接收与发送能力是否正常。(重点:双方、双向)
第二,指定自己的初始化序列号,为后面的可靠传送做准备。
第三,如果是 https 协议的话,三次握手这个过程,还会进行数字证书的验证以及加密密钥的生成到。
如果你了解 UDP 的话,TCP 的出现正式弥补了 UDP 不可靠传输的缺点。但是 TCP 的诞生,也必然增加了连接的复杂性。
四、TCP 三次握手过程?
TCP 三次握手的过程掌握最重要的两点就是客户端和服务端状态的变化,另一个是三次握手过程标志信息的变化,那么掌握 TCP 的三次握手就简单多了。下面我们就以动画形式进行拆解三次握手过程。
-
初始状态:客户端处于
closed(关闭)
状态,服务器处于listen(监听)
状态。
-
第一次握手:客户端发送请求报文将
SYN = 1
同步序列号和初始化序列号seq = x
发送给服务端,发送完之后客户端处于SYN_Send
状态。
-
第二次握手:服务端受到
SYN
请求报文之后,如果同意连接,会以自己的同步序列号SYN(服务端) = 1
、初始化序列号seq = y
和确认序列号(期望下次收到的数据包)ack = x+ 1
以及确认号ACK = 1
报文作为应答,服务器为SYN_Receive
状态。
-
第三次握手: 客户端接收到服务端的
SYN + ACK
之后,知道可以下次可以发送了下一序列的数据包了,然后发送同步序列号ack = y + 1
和数据包的序列号seq = x + 1
以及确认号ACK = 1
确认包作为应答,客户端转为established
状态。
五、为什么不是一次、二次握手?
防止了服务器端的一直等待而浪费资源。
为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。如果此时客户端发送的延迟的握手信息服务器收到,然后服务器进行响应,认为客户端要和它建立连接,此时客户端并没有这个意思,但 server 却以为新的运输连接已经建立,并一直等待 client 发来数据。这样,server 的很多资源就白白浪费掉了。
在谢希仁著《计算机网络》第四版中讲“三次握手”的目的是“为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误”。
举个简单易懂的例子,你在微信对一个女孩表白,这条信息由于网络问题延迟发送了。
然后此时你不耐烦了,去和微信另一个女孩表白,然后另一个女孩告诉你同意了,然后你心里很高兴,把高兴的心情分享给了女孩,女孩知道了你和她在一起很高兴,此时三次握完毕,你恋爱了。
突然,到了第二天,发给第一个女孩的信息才收到,女孩认为你要和他表白,此时你已经和另一个女孩恋爱了,然后第一个女孩给你发微信同意了你的表白,但是你不理睬,那个女孩还在苦苦等待你给她分享此时的高兴心情。现在我们发现如果没有分享高兴的心情给女孩(也就是第三次握手过程),那么那个女孩一直等待,白白浪费了心思,所谓的千年都等不了一回。
如果你是客户端,女孩是服务端,服务端收到延迟的报文,以为你要和它连接,所以会给你发送确认同意连接,但你一直不搭理它,所以服务端的资源也就这么白白浪费掉了。所以知道为什么要进行三次握手了吧。
在《计算机网络》书中讲“三次握手”的目的是为了解决“网络中存在延迟的重复分组”的问题。
六、为什么要 TCP 四次分手?
我们知道,TCP协议是一种面向连接的、可靠的、基于字节流的运输层通信协议,而且TCP是全双工模式。
对于初学者来说,定义太枯燥、无味,其实意思就是你和你女朋友聊天是面向连接的,只有连接起来才可以通信的,可靠就是你发送的信息可以保证送达到对方,全双工意思就是你不仅可以给你女朋友发消息,而且她也可以给你发信息。
为什么非要进行 TCP 四次分手?我们接着上回说到,你现在和第二个女孩子恋爱了,突然有一天发现第一个女孩子是因为没有收到你的表白而错过了在一起的时机,那么你要和第二个女孩子分手,那过程对应在 TCP 四次分手是怎么样子的?
你要给第二个女孩子微信发消息,我们分手吧,此时第二个女孩子收到消息知道了,非常伤心,就屏蔽了你。但是,此时你还没有屏蔽她,她完全可以给你继续发消息,她给你发消息说,好吧,此时你收到了确认消息,此时是第二次分手过程。那么女孩又给你发送消息,渣男,永远不要来找我。此时你又接收到消息,看到消息之后发了一个拜拜,然后你就直接屏蔽拉黑了对方,此时女孩微信显示你删除了对方,然后就把你也拉黑删除了。那么四次分手到此为止,恭喜你,成功获得下一个女孩子。
上述过程就阐述了为什么要进行 TCP 四次分手,为了能够让对方屏蔽你直至最后双方互相删除掉,然后你又可以和另一个女孩三次握手了。
七、TCP 四次分手过程
初始化状态:客户端和服务端都在连接状态,接下来开始进行四次分手断开连接操作。
- 第一次分手:第一次分手无论是客户端还是服务端都可以发起,因为 TCP 是全双工的。
假如客户端发送的数据已经发送完毕,发送FIN = 1 告诉服务端,客户端所有数据已经全发完了,服务端你可以关闭接收了,但是如果你们服务端有数据要发给客户端,客户端照样可以接收的。此时客户端处于FIN = 1等待服务端确认释放连接状态。
- 第二次分手:服务端接收到客户端的释放请求连接之后,知道客户端没有数据要发给自己了,然后服务端发送ACK = 1告诉客户端受到你发给我的信息,此时服务端处于 CLOSE_WAIT 等待关闭状态。
- 第三次分手:此时服务端向客户端把所有的数据发送完了,然后发送一个FIN = 1,用于告诉客户端,服务端的所有数据发送完毕,客户端你也可以关闭接受数据连接了。此时服务端状态处于LAT_ACK状态,来等待确认客户端是否收到了自己的请求。
- 第四次分手:此时如果客户端收到了服务端发送完的信息之后,就发送ACK = 1,告诉服务端,客户端已经收到了你的信息。但是我们发现上图中有一个 2 MSL 的延迟等待。
八、为什要有 2 MSL 等待延迟?
对应这样一种情况,最后客户端发送的ACK = 1给服务端的过程中丢失了,服务端没收到,服务端怎么认为的?我已经发送完数据了,怎么客户端没回应我?是不是中途丢失了?然后服务端再次发起断开连接的请求,一个来回就是2MSL,这里的两个来回由那一个来回组成的?
客户端给服务端发送的ACK = 1丢失,服务端等待 1MSL没收到,然后重新发送消息需要1MSL。如果再次接收到服务端的消息,则重启2MSL计时器,发送确认请求。客户端只需等待2MSL,如果没有再次收到服务端的消息,就说明服务端已经接收到自己确认消息;此时双方都关闭的连接,TCP 四次分手完毕。
九、如果双方建立连接,一方出问题怎么办?
如果双方建立连接,一方出问题怎么办?为了防止出现上述恋爱故事中千年等一回的情况,已经建立连接,但是服务端一直等待接收,发送端出现问题一直不能发送。
所以设计一个保活的计时器,如果一方出现问题,另一方过了这个计时器的时间,就发送试探报文,以后每隔 75 秒发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。
十、小结
今天用动画的形式给你女(男)朋友讲了 TCP 四次分手的过程,文章的内容以及展现形式是最基础的内容。
最后小鹿为大家整理的三次握手和四次分手整张图,如下: