TCP连接 关于三次握手与四次挥手

1 TCP连接中的标志位与序号

1.1 标志位

  1. SYN: Synchronize Sequence Numbers 同步序列编号,SYN是TCP建立连接时的握手信号,表示发起一次新连接
  2. ACK: 确认序号有效,用于应答
  3. FIN: 释放一个连接
  4. RST: 重置连接

1.2 序号

  1. seq: 随机产生的32位序列号,用来标识客户端发送的字节流
  2. ack: 32位确认字符序号,当ACK=1时确认序号才有效,ack=seq+1

2 三次握手

三次握手是指成功建立一次TCP连接时客户端和服务端一共发送三个数据包的过程。
三次握手的目的是确认客户端和服务端双方的发送、接收能力正常,保证TCP连接的可靠性。

三次握手的建立过程如下:

初始阶段:
客户端处于CLOSED状态,服务端处于LISTEN状态

  1. 第一次握手:
    客户端向服务端发送同步标志SYN=1,序号seq=x
    客户端进入SYN_SENT状态
  2. 第二次握手:
    服务端向客户端发送SYN=1,序号seq=y,确认标识符ACK=1,确认序号ack=x+1
    服务端进入SYN_RECV状态
  3. 第三次握手:
    客户端向服务端发送序号seq=x+1,确认标识符ACK=1,确认序号ack=y+1
    (注意,客户端、服务端向对方发送第一次请求的时候才发送同步标识符SYN,第三次握手不需要再发了)
    连接状态:
    第三次握手之后,客户端和服务端都进入已连接状态established,TCP三次握手过程完成
    三次握手

2.1 连接队列与重传机制 丢包问题

第一次握手,当服务端收到客户端的报文时,进入SYN_RCVD状态,此时还没有进入完全的连接状态,会把本次连接请求放在半连接队列里,同时向客户端发送SYN-ACK包开始第二次握手,此时如果未收到客户端的确认包,服务端则会进行首次重传,超过一定时间之后会进行后续次数的重传,这个时间一般按照指数级别增长。如果超过最大重传次数,系统就会将该连接信息从半连接队列里删除。

如果已经顺利完成三次握手进入连接状态,则会将此次连接添加到全连接队列里,如果全连接队列满了,则可能造成丢包

2.2 为什么要三次握手?两次为什么不行?

1. 需要三次握手来确保连接是可靠的

要进行可靠的通信,就必须确认客户端和服务端二者的发送、接收能力都没有问题
第一次握手,服务器收到客户端的报文,可以确认客户端的发送能力没有问题
第二次握手,客户端收到服务端的报文,可以确认服务端的接收和发送能力没有问题
但是二次握手之后,服务端并不知道客户端的接收能力有没有问题,在第三次握手,客户端在收到服务端的报文之后,给服务端发送了新的报文,此时服务端确认了客户端的接收能力没有问题,二者进入established连接状态

至此,客户端和服务端的收发能力都得到了确认,本次TCP连接的可靠性也得到了保证

2. 只进行二次握手可能会造成资源的浪费

如果客户端发出的连接请求没有收到服务端的确认,于是一段时间之后客户端又向服务端发送连接请求,成功建立连接,完成数据传输。可能存在一种情况,第一次连接并没有丢失,而是因为某个网络节点的原因延迟到达服务端,此时服务端误以为是客户端又发起新的连接,于是向客户端发出确认,完成二次握手,同时等待客户端发送数据,但客户端并不理会,从而造成服务端的资源浪费。

3 四次挥手

初始状态
客户端和服务端都为established连接状态

  1. 第一次挥手
    当客户端的数据传输完成后,客户端向服务端发出释放连接报文,标志位为FIN=1,序列号为seq=x
    客户端进入FIN_WAIT状态

  2. 第二次挥手
    服务端收到客户端发的FIN报文后给客户端回复确认报文ACK=1,确认号ack=x+1,序列号seq=y,服务端进入关闭等待状态CLOSE-WAIT,因为可能还有数据没发完,所以并不会立即发出FIN标志位
    服务端进入CLOSE_WAIT状态

  3. 第三次挥手
    服务端将最后数据发送完毕后再次向客户端发送确认报文ACK=1,FIN=1,seq=z,ack=x+1
    客户端进入LAST_ACK状态

  4. 四次挥手
    客户端受到服务端发的FIN报文后,向服务端发出确认报文ACK=1,确认号ack=z+1,seq=w。客户端在2MSL(Maximum Segment Lifetime,2个最大报文生存时长)之后释放TCP连接,服务端受到客户端发送的确认报文之后就会立马释放TCP连接,所以服务端结束TCP连接的时间要比客户端早一些
    服务端收到确认报文之后释放连接进入CLOSED状态
    客户端在等待2MSL之后进入CLOSED状态

四次挥手

3.1 为什么挥手要4次,三次不行?

断开TCP连接的前提是,客户端和服务端都没有要发送的数据了。
第一次挥手,客户端发送FIN,表示自己没有数据要发送了
第二次挥手,服务端先回复一个确认报文表示已收到客户端报文,但是自己还有一些数据没有发送完,发完了才能给FIN报文
第三次挥手,服务端确保自己数据发送完毕,给出FIN报文
第四次挥手,客户端收到服务端的FIN报文,发出确认报文,等待2MSL之后释放TCP连接,而服务端受到客户端的确认报文之后立即释放TCP连接

简而言之,三次不行是因为第二次挥手的时候服务器可能还有一些数据要发送,因此不能立即给出FIN报文,只能先给客户端一个确认报文完成第二次挥手,等待自己的数据发送完了,才在第三次挥手的时候给出FIN报文,因此多了一次挥手过程

3.2 为什么第四次挥手客户端需要等待2MSL之后才能释放TCP连接?

考虑到第四次挥手丢包的问题,如果第三次挥手后服务端没有收到返回的确认报文,就会重发第三次挥手报文,MSL是最大报文生存时间,2MSL是报文一去一回最长时间,客户端需要等待这么长时间来确认服务端已经收到第四次挥手报文

posted @ 2022-04-11 19:06  IslandZzzz  阅读(58)  评论(0编辑  收藏  举报