提示:以下是本篇文章正文内容,如有错误,请及时指正。
TCP 的连接管理机制
TCP,提供面向连接的服务,在传送数据之前必须先建立连接,数据传送完成后要释放连接。
建立连接(三次握手)
如图上所示:主机 A 想要与 主机B 建立连接,双方就都要发送同步报文段 ,而在 TCP 报头中的6位标记位中对应的 SYN 为 1 就表示该报文段是同步报文段
第一次握手:主机 A 发送一个同步报文段 SYN 给主机 B。
第二次握手:主机 B 收到这个同步报文段 SYN 之后,就知道了要双方要建立连接传数据了,就会回复一些内容给主机 A,内容就有确认应答 ACK + 同步报文段 SYN。因为在网络种传输数据开销是很大的,所以这个第二次连接就一起传输了。
第三次握手:主机 A 收到 SYN + ACK 之后就会再给主机 B 发送一个 ACK,于是通信双方就建立了。
问题一:为什么建立连接是三次握手?
答:只有经历了三次握手通信双方才能确定
对方和自己的发送能力和接收能力
都是正常的,如下图所示,按顺序阅读。
问题二:可以是两次握手吗?
答:不能,还是用上面的图,两次握手接收方 B 不能确定自己的发送能力和 A 的接收能力 OK。
问题三:可以是四次握手吗?
答:可以,把第二次握手 B 发送给 A 的 ACK 和 SYN 分两次发送,就是四次握手了,但是完全没有必要这样做,。因为它们都是由操作系统内核管理的,所以一定会发送在同一时机。
释放连接(四次挥手)
如图上所示:想要断开连接,通信双方就要发送结束报文段,FIN 为1,就表示该报文段是结束报文段
第一次挥手:主机 A 发送一个结束报文段 FIN 给主机 B。
第二次挥手:主机 B 收到这个结束报文段 SYN 之后,就知道了 A 要断开连接了,于是就会先给主机 A 发送一个确认报文 ACK (意思就是告诉主机 A ,我知道了,不过得先等一会)
第三次挥手:主机 B 向主机 A 又发送了结束报文段 FIN 。
第四次挥手:主机 A 收到这个结束报文段 FIN 后,再给主机 B 发送一个确认报文段,释放连接到此结束。
问题:断开连接时,第二次和第三次的主机 B 回复给主机 A 的 FIN 和 ACK能否合并在一起?
答:答案是不一定的。
不能合并的理由是:发送的 ACK 和 FIN 的时机是不一样的,发送 ACK 是操作系统内核的行为,在收到 FIN 的第一时间就回复了 ACK,而发送 FIN 是的应用程序的行为,需要在代码中执行到对应的 “close()” 才会触发 FIN。(这也是为什么上面提到的要等一会的原因)
能合并的理由是:如果 “close()” 能够很快被调用,FIN 和 ACK 的间隔时间很短,就会触发 TCP 的 “延时应答+捎带应答”机制,于是它俩就合并在一起了,就变成了三次挥手。
提示:关于三次握手和四次挥手的过程中也会存在数据的丢失,如果数据丢失,就会涉及到超时重传,和传输数据时一样的,想要了解这其中详细经过,可以看这个TCP 的那些事儿.
连接和释放的状态分析
如图所示
![](https://i-blog.csdnimg.cn/blog_migrate/99636c563a42dc827e4ce72a18be3174.png)
服务器端状态转化
[CLOSED -> LISTEN]
:服务器端调用listen后进入LISTEN状态, 等待客户端连接;[LISTEN -> SYN_RCVD]
:一旦监听到连接请求(同步报文段), 就将该连接放入内核等待队列中,并向客户端发送SYN确认报文.[SYN_RCVD -> ESTABLISHED]
:服务端一旦收到客户端的确认报文, 就进入ESTABLISHED状态,可以进行读写数据了.[ESTABLISHED -> CLOSE_WAIT]
:当客户端主动关闭连接(调用close), 服务器会收到结束报文段, 服务器返回确认报文段并进入CLOSE_WAIT;[CLOSE_WAIT -> LAST_ACK]
:进入CLOSE_WAIT后说明服务器准备关闭连接(需要处理完之前的数据); 当服务器真正调用close关闭连接时, 会向客户端发送FIN, 此时服务器进入LAST_ACK状态, 等待最后一个ACK到来(这个ACK是客户端确认收到了FIN)[LAST_ACK -> CLOSED]
:服务器收到了对FIN的ACK, 彻底关闭连接.
客户端状态转化:
[CLOSED -> SYN_SENT]
: 客户端调用connect, 发送同步报文段;[SYN_SENT -> ESTABLISHED]
:connect调用成功, 则进入ESTABLISHED状态, 开始读写数据;[ESTABLISHED -> FIN_WAIT_1]
:客户端主动调用close时, 向服务器发送结束报文段, 同时进入FIN_WAIT_1;[FIN_WAIT_1 -> FIN_WAIT_2]
:客户端收到服务器对结束报文段的确认, 则进入FIN_WAIT_2, 开始等待服务器的结束报文段;[FIN_WAIT_2 -> TIME_WAIT]
:客户端收到服务器发来的结束报文段, 进入TIME_WAIT, 并发出LAST_ACK;[TIME_WAIT -> CLOSED]
:客户端要等待一个2MSL(Max Segment Life, 报文最大生存时间)的时间, 才会进入CLOSED状态.