TCP协议是一种面向连接的、可靠的、基于字节流的运输层通信协议,TCP是全双工模式,需要三次握手建立连接,四次挥手关闭连接。
三次握手
三次握手(Three-way Handshake)是指建立一个 TCP 连接时,需要客户端和服务器总共发送3个报文。
三次握手的目的是连接服务器指定端口,建立 TCP 连接,并同步连接双方的序列号和确认号,交换 TCP 窗口大小信息。在 socket 编程中,客户端执行 connect() 时。将触发三次握手。 三次握手过程如下:
图片
刚开始客户段和服务器端都处于CLOSED(关闭)状态,随后服务器进程处于LISTEN(收听)状态,等待客户端的连接请求。
- 第一次握手(发送SYN):客户端向服务器发出连接请求,附带客户端序列号seq,然后进入 SYN_SENT(同步已发送) 状态,等待服务器的确认。
- 第二次握手(发送SYN+ACK):服务器收到连接请求,同意建立连接,然后向客户段发送确认连接信息,附带向客户端连接请求,此时服务器进入 SYN_RCVD(同步收到) 状态。
- 第三次握手(发送ACK):客户端收到服务器的确认连接信息,向服务器发送确认连接,此时TCP连接已经建立,客户端进入 ESTABLISHED 状态。当服务器收到客户端发送的确认报文后也会进入 ESTABLISHED 状态,完成三次握手。
为什么需要三次握手,而不是二次握手?三次握手的目的是为了防止已失效的连接请求突然又传送到了服务端,而产生错误。
假设采用两次握手建立连接,客户端第一次向服务端发送建立连接请求,因为网络延迟的原因,一直没有到达服务器。于是客户端再次向服务端重新发送建立连接请求,这次服务端收到连接请求后,向客户端回复确认,建立连接。但是这时网络延迟恢复,服务端又收到客户端第一次发送的连接请求,服务端认为客户端又发起了一次连接,再次回复确认,又建立了一个连接。
服务端认为有两个连接,客户端认为有一个连接,造成数据状态不一致。
至于为什么不像断开连接一样采用四次握手,因为服务端把确认连接请求和向客户端发送的建立连接请求合并成一次请求,发送给客户端了。
四次挥手
四次挥手是指断开一个TCP连接时,需要客户端和服务端总共发送4个报文以确认连接的断开。 四次挥手的过程如下:
图片
- 第一次挥手(发送FIN):当通信的一方完成数据发送任务,需要关闭连接时,它会发送一个FIN(结束)报文段,进入FIN_WAIT_1 状态。无论是客户端还是服务端,任何一方都可以主动发起关闭连接的请求。
- 第二次挥手(发送ACK):服务端收到FIN报文段后,发送一个ACK报文段作为回应,并进入CLOSE-WAIT状态。客户端收到ACK后,进入FIN-WAIT-2状态。这时候已经断开了客户端与服务端的连接,服务端依然可以继续向客户端发送数据。
- 第三次挥手(发送FIN):服务器端完成数据传输后,发送一个FIN报文段,请求关闭连接,进入LAST-ACK状态。
- 第四次挥手(发送ACK):客户端收到服务器的 FIN 包后,发送ACK报文段作为回应,并进入TIME-WAIT状态。经过 2MSL 后,客户端才进入 CLOSED 状态。服务器端收到客户端的确认包 ACK 后进入CLOSED 状态,连接被最终关闭。
为什么需要四次挥手?
由于TCP连接是全双工的,即数据可以在两个方向上流动,因此每个方向都必须要单独进行关闭,关闭一个方向上的连接需要一次请求和一次确认,最终需要四次请求。
为什么不能是三次,不能像建立连接那样把第二次和第三次合并成一次?
因为在第二次请求时服务端向客户端发送确认关闭连接,此时服务端可能还有一些数据没有传输完成,需要继续向客户端发送数据,不能跟合并服务器向客户端发送的关闭连接请求,所以需要拆分成两个连接请求。