【网络】TCP的三次握手、四次挥手、TIME_WAIT状态

来源:互联网 发布:渠道管控管理系统源码 编辑:程序博客网 时间:2024/06/05 09:00

       传输控制协议TCP)是一种面向连接的、可靠的、基于字节流的运输层通信协议。是专门为了在不可靠的互联网络上提供一个可靠的端到端字节流而设计的。每一次TCP连接都需要三个阶段:连接建立、数据传送和连接释放。“

下图是⼀次TCP通讯的时序图

                                         TCP连接建⽴断开


        在这个例⼦中,⾸先客户端主动发起连接、发送请求,然后服务器端响应请求,然后客户端主动关闭连接。两条竖线表⽰通讯的两端,从上到下表⽰时间的先后顺序,注意,数据从⼀端传到⽹络的另⼀端也需要时间,所以图中的箭头都是斜的。双⽅发送的段按时间顺序编号为1-10,各段中的主 要信息在箭头上标出,例如段2的箭头上标着SYN, 8000(0), ACK 1001, <mss 1024>,表⽰该段中 的SYN位置1,32位序号是8000,该段不携带有效载荷(数据字节数为0),ACK位置1,32位确认 序号是1001,带有⼀个mss选项值为1024。

建立连接的过程(三次握手):

1. 客户端发出段1,
SYN位表⽰连接请求。序号是1000,这个序号在⽹络通讯中⽤作临时的地 址,每发⼀个数据字节,这个序号要加1,这样在接收端可以根据序号排出数据包的正确顺 序,也可以发现丢包的情况,另外,规定SYN位和FIN位也要占⼀个序号,这次虽然没发数 据,但是由于发了SYN位,因此下次再发送应该⽤序号1001。 mss表⽰最⼤段尺⼨,如果⼀ 个段太⼤,封装成帧后超过了链路层的最⼤帧长度,就必须在IP 层分⽚,为了避免这种情况,客户端声明⾃⼰的最⼤段尺⼨,建议服务器端发来的段不要超过这个长度。

2. 服务器发出段2,也带有SYN位,同时置ACK位表⽰确认,确认序号是1001,表⽰“我接收到序号1000及其以前所有的段,请你下次发送序号为1001的段”,也就是应答了客户端的连接请求,同时也给客户端发出⼀个连接请求,同时声明最⼤尺⼨为1024。


3. 客户端发出段3,对服务器的连接请求进⾏应答,确认序号是8001。

在这个过程中,客户端和服务器分别给对⽅发了连接请求,也应答了对⽅的连接请求,其中服务器的请求和应答在⼀个段中发出。
       第一次握手-------客户端对服务器发出的连接请求;
       第二次握手-------服务器对客户端连接请求的确认应答并对客户端发出连接请求;
       第三次握手-------客户端对服务器连接请求的确认应答
因此⼀共有三个段⽤于建⽴连接,称为'''三次握手''。要清楚的是,在建⽴连接的同时,双⽅还协商了⼀些信息,例如双⽅发送序号的初始值、最⼤段尺⼨等。


为什么要三次握手,而不是二次握手呢?

采用三次握手的目的是为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。



  
“已失效的连接请求报文段”的产生场景:

     
        client发出的第一个连接请求报文段在传送中并没有丢失,但是在某个网络结点发生长时间滞留了,以致延误了这个请求报文本应正常连接释放的时间,最终它在之后的某个时间才到达server。此时我们知道,它已经是一个早已失效的报文段了。

     如若连接建立是二次握手。server收到此失效的连接请求报文段后,误认为是client再次发出的一个新的连接请求于是就向client发出确认应答报文段,同意建立连接。此时只要server发出确认应答,新的连接就建立了。由于此时刻client并没有发出建立连接的请求,因此不会理睬server的确认应答,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。

     但采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,server收到此失效的连接请求报文段后,向client的请求做出确认应答但并不直接建立连接,而是在确认应答的同时向client发出连接请求,由于当前client并没有发出建立连接的请求,client不会向server的请求发出确认应答。server由于收不到确认应答,就知道client并没有要求建立连接。
    

数据传输的过程:

1. 客户端发出段4,包含从序号1001开始的20个字节数据。
2. 服务器发出段5,确认序号为1021,对序号为1001-1020的数据表⽰确认收到,同时请求发送序号1021开始的数据,服务器在应答的同时也向客户端发送从序号8001开始的10个字节数 据,这称为piggyback
3. 客户端发出段6,对服务器发来的序号为8001-8010的数据表⽰确认收到,请求发送序号8011开始的数据。

     在数据传输过程中,ACK和确认序号是⾮常重要的,应⽤程序交给TCP协议发送的数据会暂存在TCP层的发送缓冲区中,发出数据包给对⽅之后,只有收到对⽅应答的ACK段才知道该数据包确实发到了对⽅,可以从发送缓冲区中释放掉了,如果因为⽹络故障丢失了数据包或者丢失了对⽅发回ACK段,经过等待超时后TCP协议⾃动将发送缓冲区中的数据包重发。

     前面的这个例⼦只描述了最简单的⼀问⼀答的情景,实际的TCP数据传输过程可以收发很多数据段,虽然典型的情景是客户端主动请求服务器被动应答,但也不是必须如此,事实上TCP协议为应⽤层提供了全双⼯(full-duplex)的服务,双⽅都可以主动甚⾄同时给对⽅发送数据。如果通讯过程只能采取⼀问⼀答的⽅式,收和发两个⽅向不能同时传输,在同⼀时间只允许⼀个⽅ 向的数据传输,则称为'''半双⼯(half-duplex)'''。

关闭连接的过程(四次挥手)
1. 客户端发出段7,FIN位表⽰关闭连接的请求。
2. 服务器发出段8,应答客户端的关闭连接请求。
3. 服务器发出段9,其中也包含FIN位,向客户端发送关闭连接请求。
4. 客户端发出段10,应答服务器的关闭连接请求。

为什么要四次挥手,而不是三次挥手呢?
     建⽴连接的过程是三⽅握⼿需要3个段,⽽关闭连接通常需要4个段,并且在关闭时,服务器对客户端关闭连接请求的应答和服务器发出的关闭连接请求通常不合并在⼀个段中。

     由于TCP连接是全双工的,因此每个方向都必须单独进行关闭可以理解为断开连接是“两个人”的事儿。由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动。因此一个TCP连接在只收到一个FIN后仍能发送数据(一个方向连接被关闭了,另一个方向还能用)。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。

    这种连接半关闭的情况是,客户端发出带有FIN位的报文表⽰关闭连接的请求,当服务器收到客户端的FIN报文通知时,它仅仅表示客户端没有数据发送给服务器了,但并不能说明此时服务器已经将所有的数据都发送给客户端了,所以服务器可能未必会马上会关闭SOCKET,而是只进行对客户端请求关闭连接的确认应答,关掉客户端方向的一条线路。然后在服务器可能还需要发送一些数据给客户端之后,服务器再发送关闭连接的请求给客户端表示现在请求完全关闭连接。所以服务器这里的ACK报文和FIN报文多数情况下都是分开发送的。

     客户端关闭连接后之后就不能再发送数据给服务器了,但是服务器还可以发送数据给客户端。直到服务器也关闭连接为⽌(完全关闭连接为止)客户端或服务器均可主动发起挥手动作在socket编程中,任何一方执行close()操作即可产生挥手操作。

四次挥手中主动断开链接的一方为什么要进入TIME_WAIT状态 ?

TCP连接是全双工通信,断开连接的主动方和被动方都需要自主关闭通信链路,TCP正常情况下连接断开会进行四次挥手:

1.由主动断开方发起FIN

2.被动方回复ACK

3.待被动方数据传输完成,被动方发送FIN

4.主动方回复ACK,并进入TIME_WAIT状态


      因为TCP是建立在非连接链路的可靠传输通信方式,在TCP连接中,当被动方发送的FIN报文到达时,主动方会发送ACK确认报文,并且进入TIME_WAIT状态,TIME_WAIT的状态会持续2MSL (MSL是报文在网络中生存的最大生命周期)。那这里主动发送方为什么要进入TIME_WAIT状态,并且TIME_WAIT状态为什么需要2MSL的状态?

有下述两个原因:

1.    若在第四次挥手时发出ACK确认应答时,由于网络原因导致ACK确认应答的报文没有被被动方收到,等到2MSL从而触发被动方重新发送FIN包,因而主动关闭连接的一方需要停留在TIME_WAIT等待状态以处理对方重新发送的FIN数据包。否则它会回应一个RST数据包给被动关闭连接的一方,引起被动方关闭流程错乱。 

2.在TIME_WAIT状态下,是不允许应用程序在当前ip和端口上与之前通信的client(这个client的ip和端口号不变)建立一个新的连接的。这样就能避免新连接收到之前的连接ip和端口一致的连接)残存在网络中的数据包了。这也是TIME_WAIT状态的等待时间被设置为2MSL的原因,以确保当前网络两个连接方向上的尚未接收到的TCP报文已经全部消失 。


原创粉丝点击