TCP连接状态及三次握手四次挥手

TCP一共有11种连接状态:

  1. SYN_SENT:在发送连接请求后等待匹配的连接请求(客户端向服务器端发送SYN请求建立一个连接,之后将状态置为SYN_SENT)

  2. FIN_WAIT_1:等待远程TCP连接中断请求,或先前的连接中断请求的确认(主动关闭端发送FIN请求主动关闭连接,之后将状态置为FIN_WAIT_1)

  3. FIN_WAIT_2:从远程TCP等待连接中断请求(主动关闭端接到ACK后,之后将状态置为FIN_WAIT_2,此时是半关闭状态,即主动关闭端还能够接受数据,但是无法发送数据 )

  4. CLOSING:等待远程TCP对连接中断的确认(如果两端同时发送FIN,则在发送后两端都进入FIN_WAIT_1状态。在收到对端的FIN后回复ACK报文,之后将状态置为CLOSING,比较少见)

  5. TIME_WAIT:等待足够的时间以确保远程TCP接收到连接中断请求的确认(主动关闭端接收到FIN,TCP就发送ACK包,之后将状态置为TIME_WAIT)

  6. LISTEN:侦听来自远方的TCP端口的连接请求(服务器端需打开一个socket进行监听,之后将状态置为LISTEN)

  7. SYN_RCVD:在收到和发送一个连接请求后等待对方对连接请求的确认(当服务器端收到客户端的连接请求后,将标志位ACK和SYN置为1发送给客户端,之后将状态置为SYN_RCVD)

  8. CLOSE_WAIT:等待从本地用户发来的连接中断请求(被动关闭端接到FIN后,就发出ACK以回应FIN请求,之后将状态置为CLOSE_WAIT)

  9. LAST_ACK:等待原来的发向远程TCP的连接中断请求的确认(被动关闭端在状态为CLOSE_WAIT一段时间后,将余下数据传送完后发回一个FIN请求关闭连接,之后将状态置为LAST_ACK)

  10. CLOSED:没有任何连接状态(被动关闭端在接受到主动关闭端ACK包,之后将状态置为CLOSED,连接结束)

  11. ESTABLISHED:代表一个打开的连接(成功建立连接,之后将状态置为ESTABLISHED,开始传输数据)

其中1-5是客户端独有的状态,6-9为服务端独有的状态,而10-11是客户端服务端公有状态。

再插入的说一下TCP的六个标志位,按在TCP首部中的顺序依次是:

1.URG(urgent紧急数据)
2.ACK(acknowlegment确认)
3.PSH(push推送)
4.RST(reset重置)
5.SYN(synchronized建立联机同步序号)
6.FIN(finish结束)

需要哪种类型则将该标志位致为1。

下图就是比较经典的TCP状态转换图:

这里写图片描述

接下来就分别通过三次握手(连接建立)和四次挥手(连接释放)说明下状态转化图。

三次握手:

这里写图片描述

建立连接前,客户端和服务端状态都为CLOSED,服务端创建socket被动打开连接,并将状态置为LISTEN。

客户端主动打开连接,向服务端发送SYN报文,将TCP首部控制位中的SYN置为1,同时序号seq为客户端随机生成的一个初始序号seq = x(SYN报文段不能携带数据,但要消耗一个序列号),并将客户端状态置为SYN_SENT。

服务端收到SYN报文后,如同意建立连接,则向客户端发送SYN+ACK报文,将TCP首部控制位中的SYN和ACK都置为1,确认号为ack = x + 1,同时随机生成一个自己的序号seq = y,并将服务端状态致为SYN_RCVD(同步收到状态)。

客户端收到SYN+ACK报文后,还需向服务端发送ACK报文,将TCP首部控制位中的ACK置为1,确认号ack = y + 1,序列号seq = x + 1,并将客户端状态置为ESTABLISHED。

服务端收到ACK报文后,也将状态置为ESTABLISHED,此时三次握手完成,连接建立,进入数据传送状态。

为什么要三次握手而不是两次:

现假定出现一种异常情况:客户端发送的SYN报文并未丢失,而是在某个网络节点长时间滞留了,以致延误到客户端连接释放后的某个时间才到达服务端,但服务端收到此失效的SYN报文后,误以为是客户端又发出的一次新的连接请求,于是就向客户端发出SYN+ACK报文段,同意建立连接,假定不采用三次握手而是两次握手,服务端就认为连接已经建立,并一直等待客户端发送数据,但由于这次连接在客户端已经失效了,因此不会对服务端的SYN+ACK报文给予回应,这就造成了服务端许多资源的白白浪费,所有才有三次握手的办法可以防止上述现象的发生,即防止已失效的SYN报文突然又传回服务端,因为产生错误。例如上述的情况,客户端不向服务端发回ACK报文,由于客户端收不到ACK报文,就知道客户端并未要求建立连接,也不会造成资源的白白浪费,但三次握手也是有一定缺陷的,会被利用发起SYN flood攻击。

四次挥手:

这里写图片描述

TCP连接是全双工的,所以释放连接会比建立连接略微复杂,释放连接前,两端都处于ESTABLISHED数据传输状态。

客户端先向服务器端发送FIN报文,将TCP首部控制位中的FIN置为1,其序号seq = u,u等于客户端前面最后一个已传送过的包seq,并将状态置为FIN_WAIT_1,等待服务端的确认。

服务端收到FIN报文后,将发送ACK报文,确认号ack = u + 1,序号seq = v,v等于服务端前面最后一个已传送过的包的seq,之后将状态致为CLOSE_WAIT(此时TCP连接处于半关闭状态,即客户端已经没有数据要发送了,但若服务端要发送数据,客户端仍要接受,也就是说服务端到客户端这个方向的连接并未关闭,这个状态可能会持续一段时间)。

当客户端收到服务端传来的确认报文后,将状态致为FIN_WATI_2,等待服务端发送的FIN+ACK报文段。

若服务端没有要向客户端发送的数据,其应用进程就通知TCP释放连接,将FIN+ACK报文段TCP首部控制位FIN和ACK置为1,此时序号seq = w(因为之前可能又传递一些数据),确认号ack = u + 1(上次的确认号),并将状态置为LAST_ACK。

客户端收到服务端的FIN+ACK报文后,需发送确认报文段,确认号ack = w + 1,序列号为seq = u + 1,并将状态置为TIME_WAIT状态,现在TCP连接还没有释放掉,必须经过2MSL(Max Segment Lifetime 最长报文段寿命)后才能进入CLOSED状态,服务端在接受到确认报文后将状态置为CLOSED。

上述的TCP连接释放过程是四次挥手。

为什么四次挥手:

TCP连接是全双工的,当关闭连接时,当收到客户端的FIN报文时,仅仅表示客户端没有数据发送给服务端了;但未必服务端所有的数据都发送给客户端了,所以服务端未必会马上会关闭SOCKET,也即服务端可能还需要发送一些数据给客户端之后,再发送FIN+ACK报文给客户端来表示现在可以关闭连接了,所以服务端这里的ACK报文和FIN报文多数情况下都是分开发送的以确保数据能够完成传输。

为什么TIME_WAIT状态必须等待2MSL时间

1.保证客户端发送的最后一个ACK报文能够到达服务端:

客户端发送的最后一个ACK报文段可能会丢失,而处在LAST_ACK状态的服务端因收不到客户端的ACK报文会超时重传FIN+ACK报文,因此客户端就能在2MSL时间内收到这个重传的FIN+ACK报文并重传一次ACK报文,同时也重新启动2MSL计时器,这样客户端服务端都能正常进入CLOSED状态。如果客户端不在TIME_WAIT状态下等待一段时间,而是在发完ACK报文就进入CLOESD状态释放连接,那么一旦这个ACK报文丢失,服务端收不到此ACK报文就无法正常进入CLOESD状态。

2.防止已失效的SYN报文出现在此次连接中:

客户端在发送完最后一个ACK报文经过2MSL后,就可以使此次连接持续的时间内所产生的所有报文从网络中消失,这样就能确保下一次新的连接中不会出现旧的连接请求报文。

最后再结合wireshark详细看一下三次握手,四次挥手的过程:

三次握手:

这里写图片描述

可以看到该包为SYN包,并且seq = 54778471

这里写图片描述

该包为SYN+ACK包,ack = 54778471 + 1 = 54778472;seq = 720032937

这里写图片描述

该包为ACK包, ack = 750032937 + 1 = 750032938;seq = 54778472

至此,三次握手连接建立完成,两端开始传输数据。

四次挥手:

这里写图片描述

这个是客户端发送的最后的包,其中seq = 54779313;ack=720114520;

这里写图片描述

这个是客户端主动发起的FIN包,seq =54779313;ack = 720114250

这里写图片描述

这是服务端回的FIN+ACK包,因为CLOSE_WAIT下没有数据,所以两个过程合一块了,seq = 720114250, ack = 54779313 + 1 = 54779314

这里写图片描述

这是客户端回的最后一个ACK包,seq = 54779314;ack = 720114250 + 1 =720114251

至此,四次握手连接释放完成,两端进入CLOSED状态。

数据传递

这里写图片描述

这是服务端传送数据的一个包,seq = 720033157;ack = 54778889,len = 1440

这里写图片描述

这是客户端收到数据后发的确认包,可见seq = 54778889;ack = 720033157 + len = 720034597

可知:
客户端seq = 上个服务端包ack值,ack = 上个服务端包seq + len值
服务端seq = 上个客户端包ack值,ack = 上个客户端包seq + len值

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值