您的位置:首页 > 理论基础 > 计算机网络

TCP的三次握手和四次挥手详解

2017-07-14 21:50 351 查看
我们在上一篇博客中介绍了TCP服务和分析TCP的首部,而今天讲的三次握手与四次挥手也会用到TCP的首部,不太清楚的小伙伴可以阅读一下:TCP报文段首部分析

TCP的三次握手

TCP以全双工方式传送数据。在任何数据传送之前,要使每一方能确知对方的存在。双方都必须对通信进行初始化,并得到对方的认可。当两个TCP建立连接后,他们就能够同时互相发送报文段。

TCP中建立连接采用3次握手的方式实现。建立连接的过程从服务器开始。服务器先发出一个被动打开的命令,告诉它的TCP它已经准备好接受客户进程连接请求,即被动的等待握手。客户进程发出主动打开命令,表明要与一个服务器应用进程使用传输层协议中的TCP建立传输连接,即发送建立连接请求。TCP建立连接3次握手的过程入下图:



3次握手具体步骤:

B的TCP服务器进程先创建传输控制模块TCB(存储了每一个连接中的一些重要信息,如,TCP连接表,当前发送和接收的序号等),准备接受客户进程的连接请求,然后服务器进程就处于LISTEN(收听)状态,等待客户的连接请求,如果有,立即做出响应。

第一次握手:A的TCP客户端也首先创建传输控制模块TCB,然后向B发出连接请求报文段。此时首部中的同部位SYN=1(请求报文),同时选择一个初始序号 seq = x,**TCP规定,SYN报文段(即 SYN=1的报文段)不能携带数据,但要消耗一个序号。此时,TCP客户端进入**SYN-SENT(同步已发送)状态。

第二次握手:B收到连接请求报文段后,如果同意建立连接,则向A发送确认保温。在确认报文段中应把SYN和ACK都置1(同意建立连接)确认号是ack=x+1,同时自己选择一个初始序号seq=y。这时TCP服务器进入SYN-RCVD(同步收到)状态。

第三次握手:TCB客户进程A收到B的确认后,还要向B给出确认。确认报文段的ACK置1,确认号ack=y+1,自己的序号seq=x+1。 此时,TCP连接已经建立,A进入ESTABLISHED(已建立连接)状态。

为什么是三次握手,两次握手行不行?

假如我们采用两次握手,如果A发送一个连接请求报文,但是这个报文在网络节点长时间滞留了,没有按时递达服务器端。在重传计时器的计时到达之后,客户端再次向服务端发送请求连接报文,而第二个报文成功到达服务器成功建立连接,数据传输完毕后,就释放了连接。但是,第一个请求报文在网络中滞留很长时间,在服务器与客户端数据传输完毕,断开连接后到达服务器。服务器误认为这个已经失效的报文是A再一次发出的连接请求。于是就向A发送确认报文,同意建立连接,因为认为是采用二次握手,那么此时认为新的连接已经建立。

由于A并没有发出建立连接请求,因此不会理财B的确认,也不会向B发送数据。但B却认为新的连接运输连接已经建立,并一直等待A发来数据。B的许多资源就这样拜拜浪费了。

采用三次握手就可以防止上述现象发生,例如在刚才的情况下,A不会向B的确认发出确认。B由于收不到确认,就知道A并没有要求建立连接。

TCP的四次挥手

由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。

TCP连接释放过程相对来说比连接过程要复杂一点:



第一次挥手:A的应用进程先向其TCP发出连接释放报文段,并停止再发送数据。主动断开TCP连接。A把连接释放报文段首部的终止控制位FIN置1,其序号seq=u。此时A进入FIN-WAIT-1(终止等待1)状态。

第二次握手:B收到连接释放报文段后立即发送确认。确认号是ack=u+1,而这个报文段自己的序号是v,然后B就进入了CLOSE-WAIT(关闭等待)状态、TCP服务器进程这时应通知高层应用进程,因而A到B这个方向的连接就释放了,这个是的TCP连接就处于半关闭状态,即A已经没有数据要发送了,但B若发送数据,A仍要接收。换句话说,从B到A方向的连接并未关闭,这个状态要持续一些时间。

A收到B的确认,就进入FIN-WAIT-2(终止等待 2)状态,等待B发出的连接释放报文段。

第三次握手:若B已经没有想A发送的数据,其应用进程就通知TCP释放连接。这时B发送一个FIN=1,假定B的序号为w,确认号ack=u+1的报文。此时B进入LAST-ACK(

最后确认)状态,等待A的确认。

第四次握手:A在收到B的连接释放报文段后,必须对此发出确认。在确认报文段中把ACK置1,确认号ack=w+1,自己的序号seq=u+1。

然后进入到TIME-WAIT(时间等待)状态。

注意:此时的TCP连接还没有释放掉,必须经过时间等待计时器(TIME-WAIT timer)设置的时间2MSL后,A才进入到CLOSED状态。

B只要收到A发送的确认,就进入CLOSED状态。

建立连接只需要三次握手,那么为何关闭连接需要四次挥手?

这是因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方也未必全部数据都发送给对方了,所以己方可以立即close,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送。

TIME_WAIT状态

TIME_WAIT表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后即可回到CLOSED可用状态了。如果FIN_WAIT_1状态下,收到了对方同时带 FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。

TIMEWAIT状态本身和应用层的客户端或者服务器是没有关系的。仅仅是主动关闭的一方,在使用FIN|ACK|FIN|ACK四分组正常关闭TCP连接的时候会出现这个TIMEWAIT。服务器在处理客户端请求的时候,如果你的程序设计为服务器主动关闭,那么你才有可能需要关注这个TIMEWAIT状态过多的问题。如果你的服务器设计为被动关闭,那么你首先要关注的是CLOSE_WAIT。

TCP要保证在所有可能的情况下使得所有的数据都能够被
4000
正确送达。当你关闭一个socket时,主动关闭一端的socket将进入TIME_WAIT状态,而被动关闭一方则转入CLOSED状态,这的确能够保证所有的数据都被传输。当一个socket关闭的时候,是通过两端四次握手完成的,当一端调用close()时,就说明本端没有数据要发送了。这好似看来在握手完成以后,socket就都可以处于初始的CLOSED状态了,其实不然。原因是这样安排状态有两个问题, 首先,我们没有任何机制保证最后的一个ACK能够正常传输,第二,网络上仍然有可能有残余的数据包(wandering duplicates),我们也必须能够正常处理。

TIMEWAIT就是为了解决这两个问题而生的。

1.假设最后一个ACK丢失了,被动关闭一方会重发它的FIN。主动关闭一方必须维持一个有效状态信息(TIMEWAIT状态下维持),以便能够重发ACK。如果主动关闭的socket不维持这种状态而进入CLOSED状态,那么主动关闭的socket在处于CLOSED状态时,接收到FIN后将会响应一个RST。被动关闭一方接收到RST后会认为出错了。如果TCP协议想要正常完成必要的操作而终止双方的数据流传输,就必须完全正确的传输四次握手的四个节,不能有任何的丢失。这就是为什么socket在关闭后,仍然处于TIME_WAIT状态的第一个原因,因为他要等待以便重发ACK。

2.假设目前连接的通信双方都已经调用了close(),双方同时进入CLOSED的终结状态,而没有走TIME_WAIT状态。会出现如下问题,现在有一个新的连接被建立起来,使用的IP地址与端口与先前的完全相同,后建立的连接是原先连接的一个完全复用。还假定原先的连接中有数据报残存于网络之中,这样新的连接收到的数据报中有可能是先前连接的数据报。为了防止这一点,TCP不允许新连接复用TIME_WAIT状态下的socket。处于TIME_WAIT状态的socket在等待两倍的MSL时间以后(之所以是两倍的MSL,是由于MSL是一个数据报在网络中单向发出到认定丢失的时间,一个数据报有可能在发送途中或是其响应过程中成为残余数据报,确认一个数据报及其响应的丢弃的需要两倍的MSL),将会转变为CLOSED状态。这就意味着,一个成功建立的连接,必然使得先前网络中残余的数据报都丢失了。

大量TIMEWAIT出现,并且需要解决的场景

在高并发短连接的TCP服务器上,当服务器处理完请求后立刻按照主动正常关闭连接。这个场景下,会出现大量socket处于TIMEWAIT状态。如果客户端的并发量持续很高,此时部分客户端就会显示连接不上。

我来解释下这个场景。主动正常关闭TCP连接,都会出现TIMEWAIT。为什么我们要关注这个高并发短连接呢?有两个方面需要注意:

高并发可以让服务器在短时间范围内同时占用大量端口,而端口有个0~65535的范围,并不是很多,刨除系统和其他服务要用的,剩下的就更少了。

在这个场景中,短连接表示“业务处理+传输数据的时间 远远小于 TIMEWAIT超时的时间”的连接。这里有个相对长短的概念,比如,取一个web页面,1秒钟的http短连接处理完业务,在关闭连接之后,这个业务用过的端口会停留在TIMEWAIT状态几分钟,而这几分钟,其他HTTP请求来临的时候是无法占用此端口的。单用这个业务计算服务器的利用率会发现,服务器干正经事的时间和端口(资源)被挂着无法被使用的时间的比例是 1:几百,服务器资源严重浪费。

综合这两个方面,持续的到达一定量的高并发短连接,会使服务器因端口资源不足而拒绝为一部分客户服务。

虽然它存在着这种问题,但是我们还是需要要抱着一个友好的态度来看待它,因为它尽它的能力保证了服务器的健壮性。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  tcp 通信 博客