详解TCP的三次握手和四次挥手
开始之前先回顾一下我们在计算机网络课堂上学习的TCP报文的头部结构
1 TCP报文的头部结构
如上图所示,大致了解一下:
- source port :16位源端口号
- destination port:16位目标端口号
- sequence number:32位序列号,简写为seq
- acknowledgment number(if ack set):32位确认号,简写为ack
重点了解:
- 序号:seq序号,占32位,用来标识从TCP端发送的字节流,发起方发送的数据对此进行标识。
- 确认序号:ack序号,占32位,只有当ack标志位置为1时,确认号字段才有效,ack = seq + 1.
- 标志位:共6个,即URG、ACK、PSH、RST、SYN、FIN
- URG:紧急指针(urgent point)有效。
- ACK:确认序列号有效。
- PSH:接收方应该尽快将这个报文交给应用层。
- RST:重置连接
- SYN:发起一个新的连接
- FIN:释放一个连接
注意:
- 不要将确认序号ack和标志位中的ACK搞混。
- 接收方 ack = 发起方 seq + 1,两端口匹配
2 三次握手
三次握手的本质是确认通信双方收发数据的能力。假设收发件我们记为
-
首先,我让信使运输一封信件给对方,对方收到了。那么对方他就知道了我的发件能力和他的收件能力是OK的。
-
然后,对方给我回信,我收到了。于是我便知道我的发件能力和他的收件能力是OK的,并且他的收件能力也是OK的。
此时,对方还不知道他自己的发件能力和我的收件能力是否OK,因此我需要再回复他一下。
- 最后,我再回复他一下,对方收到了,他便知道了他的发件能力和我的收件能力是可以的。
- 第一次握手:客户端要向服务端发起连接请求,首先客户端随机生成一个起始序列号 ISN(比如是100),那客户端向服务端发送的报文段包含 SYN 标志位(也就是 SYN = 1),序列号 seq = 100。
- 第二次握手:服务端收到客户端发过来的报文后,发现 SYN = 1,知道这是一个连接请求,于是将客户端的其实序列号100存起来,并且随机生成一个服务端的起始序列号(比如是200)。然后给客户端回复一段报文,回复报文包含 SYN 和 ACK 标志(也就是 SYN = 1, ACK = 1)、序列号 seq = 200、确认号 ack = 101(客户端的序列号 + 1)。
- 第三次握手:客户端收到服务端的回复后发现 ACK = 1 并且 ack = 101,于是知道服务端已经收到了序列号为 100 的那段报文;同时发现 SYN = 1,知道了服务端同意了这次连接,于是就将服务端的序列号 200 给存下来。然后客户端再回复一段报文给服务端,报文包含 ACK 标志位(ACK = 1)、ack = 201(服务端序列号 + 1)、seq = 101(第一次握手时发送报文是占据一个序列号的,所以这次 seq 从101 开始,需要注意的是不携带数据的 ACK 报文是不占据序列号的,所以后面第一次正式发送数据时 seq 还是101)。当服务端收到报文后发现 ACK = 1 并且 ack = 201,就知道客户端收到序列号为300 的报文了,就这样客户端和服务端通过 TCP建立了连接。
3 四次挥手
四次挥手的目的是关闭一个连接。
比如说客户端初始化的序列号 ISA = 100。服务端初始化的序列号 ISA = 200。 TCP 连接成功后客户端总共发送了1000个字节的数据,服务端在客户端发 FIN 报文前共回复了 2000个字节的数据。
- 第一次挥手:当客户端的数据都传输完成后,客户端向服务端发出释放报文(当然数据没发完时也可以发送连接释放报文并停止发送数据),释放连接报文包含 FIN 标志位(FIN = 1)、序列号 seq = 1101 ( 100 + 1 + 1000,其中的 1 是建立连接时占的一个序列号)。需要注意的是客户端发出 FIN 报文段后只是不能发数据了,还是可以正常接收数据;另外 FIN 报文段即使不携带数据也要占据一个序列号。
- 第二次挥手:服务端收到客户端发的 FIN 报文后给客户端回复确认报文,确认报文包含 ACK 标志位(ACK = 1)、确认号 ack = 1102(客户端 FIN 报文序列号 1101 + 1)、序列号 seq = 2200(200 + 2000)。此服务端处于关闭等待状态,而不是立马给客户端发送 FIN 报文,这个状态还有持续一段时间,因为服务端可能还有数据没发完。
- 第三次挥手:服务端将最后数据(比如50个字节)发送完毕后就向客户端发出连接释放报文,报文包含 FIN 和 ACK 标志位(FIN = 1,ACK = 1)、确认号和第二次握手的一样 ack = 1102、序列号 seq = 2250(2200 + 50)。
- 第四次挥手:客户端收到服务端发的 FIN 报文后,向服务端发出确认报文,确认报文包含 ACK 标志位(ACK = 1)、确认号 ack = 2251、序列号 seq = 1102。注意客户端发出确认报文后不是立马释放 TCP连接,而是要经过 2MSL(最长报文段寿命的2倍时长)后才释放 TCP 连接。而服务端一旦收到客户端发出的确认报文就会立马释放 TCP 连接,所以服务端结束 TCP 连接的时间要比客户端早一些。