TCP的三次握手与四次挥手
1. TCP的特点
- TCP协议是全双工通信,即收发双发可以同时给对方发送消息,即A给B发送消息的同时,B也可以给A发送消息。而且双方谁先发起请求都可以。
- TCP协议是可靠通信:因为TCP协议有ack,即消息确认机制。
- 面向连接的:收发消息之前双方要先建立起连接,即三次握手。
- 长连接:会一直占用双发的端口。
- 流式传输:能够传输的数据长度几乎没有限制。流式传输我的理解就像流水一样,数据不间断,所有数据都连接在一起,当然并不是真的都连在一起,只是TCP内部为了尽量减少发送包的数量。由于TCP的优化算法,TCP发送消息时,并不会立即发送出去,而是会等一下,会尽量等发送端的缓冲区满了才会发送消息,如果发送的数据比较小,并且在时间范围内没有其他数据进来就会直接发送。
2. TCP的三次握手
-
第一次握手:客户端A向服务端B发送一个SYN=1链接请求,以及一个初始序列号seq=x,并进入SYN_SEND状态,等待服务器B确认。
-
第二次握手:服务端B接收到客户端A发来的SYN=1链接请求,并进行确认ack=x+1,即告诉客户端A我可以接收你接下来发送序列号为x+1的消息。同时服务器B也会向客户端A发送一个syn链接请求,以及一个初始化序列号seq=y,此时服务器B进入SYN_RECV状态。
-
第三次握手:客户端A接收到服务器发送的syn+ack确认包,向服务器B发送一个ack=y+1的确认包,即告诉服务器B我已经准备好接收你发送的序列号为y+1的数据。此时连接建立。
为什么不能是两次握手?
- 如果建立连接只需两次,那么客户端A向服务器B发送连接请求,如果此时网络延迟,客户端A的消息没有发送到服务器B,此时客户端A会重新发送请求,如果服务器B接收并正确应答,此时双方开始通信,通信结束后释放资源。但是,如果这个时候那个失效的连接请求到达服务器,服务器B接收到之后,会给客户端A回复应答消息,并请求建立连接,因为只有两次,此时服务器会认为已经建立连接,但是此时的客户端已经关闭,会导致服务器的这个端口一直被占用,如果这种情况较多,就会浪费服务器的连接资源。
为什么不能是四次握手?
- 如果是四次挥手,就会造成不必要的浪费,三次之后,A和B之间就可以互相通信了。
3. TCP的四次挥手
-
TCP协议是全双工通信,双方均可进行关闭操作。
-
第一次挥手:客户端A主动发起关闭请求,给服务端B发送一个Fin=1关闭请求,以及一个初始序列号seq=u,此时客户端A进入FIN-WAIT-1状态。注:seq=u-1的消息是客户端A发送出的最后一个字节的序列号。
-
第二次挥手:服务端B收到客户端A发来的Fin关闭请求后,给客户端A回复一个ACK=1,ack=u+1的确认报文,并携带上自己的序列号seq=v,服务端B就进入了CLOSE-WAIT(关闭等待)状态。ACK是确认好是否有效的标识,一般设置为1。
客户端A收到该应答,进入FIN-WAIT-2状态,等待B发送连接释放请求。(在这之前可能还需要接受服务器发送的最后的数据)。
-
第三次挥手:服务器很可能又发送了一些数据,假定此时的序列号为seq=w,服务端B数据发送完毕后,服务器B向客户端A发送连接释放报文,内容包括:FIN=1,ACK=1,ack=u+1,seq=w,此时服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
-
第四次挥手:客户端A接收到服务器发送的连接释放报文后,给服务端B回复ACK=1,ack=w+1的确认报文,而自己的序列号是u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。此时,TCP连接还没有释放,需要等待2*MSL(最大报文段生存时间)时间后,若该时间段内没有服务器B的重发请求的话,客户端A就进入CLOSED状态,并撤销TCB。当服务器B收到确认应答后,也便进入CLOSED状态,撤销TCB。
TCB 是传输控制模块的缩写,是某个TCP连接中保存通讯双方特征信息的一个结构体。
为什么最后客户端还要等待 2*MSL的时间呢?
MSL(Maximum Segment Lifetime),TCP允许不同的实现可以设置不同的MSL值,即最大报文段生存时间。
第一,保证客户端发送的最后一个ACK报文能够到达服务器,因为这个ACK报文可能丢失,站在服务器的角度看来,我已经发送了FIN+ACK报文请求断开了,客户端还没有给我回应,应该是我发送的请求断开报文它没有收到,于是服务器又会重新发送一次,而客户端就能在这个2MSL时间段内收到这个重传的报文,接着给出回应报文,并且会重启2MSL计时器。
第二,防止类似与“三次握手”中提到了的“已经失效的连接请求报文段”出现在本连接中。客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样新的连接中不会出现旧连接的请求报文。
为什么不是三次挥手?而是四次挥手?
因为当服务器确认客户端断开请求之后,服务端可能还有数据需要发送,所以要等数据发送完毕之后,服务端再发送断开连接请求。需要等待消息完全发送完毕,所以挥手多了一次。