三次握手
第一次握手:客户端向服务端发送请求连接的SYN报文,客户端进入SYN_SENT状态,等待服务端确认;
第二次握手:服务端收到客户端的SYN报文,对SYN报文段进行确认,并向客户端发送SYN+ACK报文,服务端进入SYN_RCVD状态;
第三次握手:客户端收到服务端的SYN+ACK报文,设置ACK报文,向服务端发送ACK报文,这个报文发送完毕后,客户端和服务端都进入了ESTABLISH状态,TCP连接成功,三次握手完成;
四次挥手
状态码的变化第一次挥手:客户端向服务端发送断开连接的FIN报文,客户端进入FIN_WAIT状态,表示没有数据要发送给服务端了;
第二次挥手:服务端收到客户端发送的FIN报文,向客户端发送ACK报文;
第三次挥手:服务端向客户端发送请求关闭连接的FIN报文,服务端进入LAST_ACK状态;
第四次挥手:客户端收到服务端发送的FIN报文,向服务端发送ACK报文,客户端进入TIME_WAIT状态。服务端收到客户端发送的ACK报文后,关闭连接;此时如果客户端等待响应的时间超过报文最大生存时间,则说明服务端已经正常关闭,客户端也可以关闭连接了;
为什么TCP建立连接需三次握手?
防止服务端因收到了早已过期失效的客户端请求连接报文,而不断等待客户端的请求,从而造成死锁状态,浪费资源。因为如果在第一次握手的时候,也就是客户端发送请求连接的报文给服务端时,如果此报文因为某种原因在网络节点上长时间滞留,导致延迟到连接释放之后的某个时间才到达服务端,那么这时候服务端会认为是客户端重新发送的新的请求连接报文,但实际上已经是失效的报文。如果只是经过二次握手,那么第二次握手服务端向客户端发送确认请求连接报文并建立连接,这个时候就会导致客户端并没有建立连接,而服务端已经建立连接的情况,那么服务端就会一直等待客户端发送请求数据,而客户端因未建立连接并不会发起任何请求,从而造成死锁状态。如果采用三次握手就不会出现上述情况,因为第三次握手时客户端知道自己的报文已经失效了,不会向服务端发送的确认连接报文进行再次确认,当服务端没有再次收到客户端再次确认请求连接的报文时就会知道客户端并无建立TCP连接的请求,故服务器也就不会一直等待客户端发送请求了。
为什么建立连接协议是三次握手,而关闭连接却是四次挥手呢?
TCP是全双工的双向通信方式,即连接双方都可以发送和接受数据,在断开TCP连接时需要双方都关闭连接,才算真正关闭TCP连接,否则如果只有一方断开连接,那就只是处于TCP半关闭状态。
第一次挥手客户端发起释放连接的请求给服务端,表示没有数据要发送给服务端了;第二次挥手服务端返回确认释放连接的报文给客户端,此时客户端到服务端的连接已经关闭,但是服务端到客户端的连接依然存在,服务端依然可以返回响应数据给客户端,TCP出于半关闭状态;所以服务端需要进行第三次挥手,发送释放连接的报文给客户端,表示没有数据要发送给客户端了,客户端收到报文后再返回确认释放连接的报文给服务端,并等待服务端的关闭,当服务端收到客户端的释放连接报文后就关闭连接,客户端等待超过报文最长生存时间后也关闭连接,此时服务端到客户端的连接才真正释放,即TCP连接真正关闭。
第一次挥手时客户端发送FIN报文给服务端仅表示及没有数据要发送给服务端了,但是这时候可能服务端还有数据要传输给客户端,所以不能同时发送ACK报文和FIN报文马上断开连接,需要先发送ACK报文通知客户端数据已经传输完成了,再发送FIN报文进行确认关闭连接的信息通知客户端,所以需要进行四次挥手。
为什么客户端关闭连接前要等待2MSL时间?
原因是最后一次客户端发送的确认连接释放的请求有可能会失效(第四次挥手),如果失效了服务端就接收不到确认连接的报文,那么这时候服务端会重新发送释放连接的报文(第三次挥手),如果此时客户端没有等待2MSL时间直接关闭连接的话,那么客户端就会接收不到服务端再次发送的释放连接报文,此时客户端处于关闭状态,但是服务端处于未关闭状态,导致TCP断开连接失败。
参考
《Android进阶之光》 第5章 5.2 TCP的三次握手与四次挥手
网友评论