TCP协议是一种面向连接(三次握手)、可靠的(确认机制)、基于字节流的传输层的通信协议。
TCP的三次握手
- 客户端采用TCP协议将带有SYN标志的数据包发送给服务端,请求建立连接。
- 服务端在接受到客户端的SYN包之后,必须确认SYN,即发送自己的ACK标志。同时,自己也会向客户端发送一个SYN标志(应答客户端,请求建立连接)
-
客户端在接受到服务端的SYN+ACK包之后,会向服务端发送一个ACK标志,针对服务端请求进行应答。那么客户端和服务器正式建立了连接,开始传输数据。
TCP的三次握手.png
为什么不能是两次握手?
- 为了实现可靠数据传输, TCP 协议的通信双方, 都必须维护一个序列号, 以标识发送出去的数据包中, 哪些是已经被对方收到的。 三次握手的过程即是通信双方相互告知序列号起始值, 并确认对方已经收到了序列号起始值的必经步骤
- 如果只是两次握手, 至多只有连接发起方的起始序列号能被确认, 另一方选择的序列号则得不到确认。(服务器并不能保证客户端已经收到了第二次的请求)
TCP四次挥手
四次挥手是用来断开服务器和客户端之间的通信的,之所以要断开连接,是因为TCP/IP 协议是要占用端口号的,而计算机的端口却是有限的,不进行断开的话,势必会造成计算机资源的浪费。
- 客户端发送关闭请求
- 服务端响应客户端关闭请求
- 服务端发送关闭请求
- 客户端发送关闭确认请求

关闭的时候为什么需要四次挥手?
关闭连接时,当服务端发送FIN报文时,很可能不会立即关闭socket,所以只能先回复一个ACK报文,告诉客户端,你的FIN报文我收到了。等我服务端所有的报文发送完了,我才能发送FIN报文,因此FIN和ACK报文不能一起发送,需要四次挥手。
TCP状态中TIME_WAIT的作用
客户端接收到服务器端的 FIN 报文后进入此状态,此时并不是直接进入 CLOSED 状态,还需要等待一个时间计时器设置的时间(等待2MSL,MSL是数据包在网络中生存的最大生存时间)。这么做有两个理由:
- 确保最后一个确认报文段能够到达。如果 B 没收到 A 发送来的确认报文段,那么就会重新发送连接释放请求报文段,A 等待一段时间就是为了处理这种情况的发生。(为实现TCP全双工连接的可靠释放)
- 可能存在已失效的连接请求报文段,为了防止这种报文段出现在本次连接之外,需要等待一段时间。(为使旧的数据包在网络因为过期而消失)
TIME_WAIT状态如何避免
首先服务器可以设置SO_REUSEADDR套接字选项来通知内核,如果端口忙,但TCP连接位于TIME_WAIT状态时可以重用端口。在一个非常有用的场景就是,如果你的服务器程序停止后想立即重启,而新的套接字依旧希望使用同一端口,此时SO_REUSEADDR选项就可以避免TIME_WAIT状态。
网友评论