TCP协议C/S模型总结(状态转移篇)

TCP协议C/S模型总结(状态转移篇)


花女士曾经说过:“离家太远会忘记故乡,…”,长时间在应用层面去做需求就会开始忽视掉一些最底层的知识和逻辑,一些自以为很简单的东西可能往往都只是浮于表面,最近开始回顾和提炼一些重要的东西,加深印象的同时希望能了解到一些新的东西吧!

状态转移图

状态转移图

这里我们对TCP的11个状态进行一一分析:

CLOSED :

整个流程图的起始状态和终结状态,在超时或者连接关闭的时候才会进入该状态。即TIME_WAIE状态等待2MSL后或者SYN_SENT超时,又或者服务器被动关闭后会该状态。

SYN_SENT :

客户端发起第一次握手后,客户端处于该状态;即第一个SYN发出后,客户端的状态由CLOSED状态转换到SYN_SENT状态。这里会等待服务器响应[SYN ACK]报文后,向服务器发送ACK报文,此时客户端状态由SYN状态转移到ESTABLISHED状态。如果等待超时,则连接建立失败,SYN_SENT状态直接转移为CLOSED状态。

ESTABLISHED:

客户端进入该状态后表明已经准备好做数据收发业务了。上面说到客户端在发出第三次握手信息后立即进入ESTABLISHDED状态,而服务器要在接收到这一包ACK之后才会从SYN_RECV状态进入到ESTABLISHED状态

LISTEN:

这里指的是服务器等待连接的状态。服务器经过socket,bind,listen这些函数之后就进入了该状态。开始监听客户端发送过来的连接请求。即服务器在接受到客户端发送过来第一个SYN后并向客户端发送[SYN ACK]报文后状态转移到SYN_RECV状态。

SYN_RCVD:

状态图中还描述了一种情况,当客户端在发送SYN的同时也收到服务器端的SYN的请求,即两个同时发起请求,那么客户端就会从SYN_SENT状态转化到SYN_REVD状态。

FIN_WAIT_1:

主动关闭的一方做完数据业务后,准备终止连接,在发送第一个FIN之后进入FIN_WAIT1状态等待对端的ACK,也就是所谓的第一次挥手。

FIN_WAIT_2:

主动发起断开的一方在接受到对端的ACK(第二次握手信息)之后,进入到FIN_WAIT2状态。

CLOSING:

主动方发送完FIN后就进入了FIN_WAIT1状态等待ACK,但是却没有等来ACK,反而等来了被动方的FIN报文,这说明被动方也发起了主动关闭请求,主动方回复ACK后,进入CLOSIONG的状态。

TIME_WAIT:

从上面的额状态转移图可以看出,TIME_WAIT状态是四次挥手操作最后都会经过的状态,我们分别从三个转移过程分别描述:

  • 由CLOSING状态进入TIME_WAIT状态

也就是主被动双方同时发起关闭的状态下,当主动方接受到ACK后,进入到这个状态

  • 由FIN_WAIT1进入TIME_WAIT状态

主动方在FIN_WAIT1状态下,正好被动方也发起了关闭请求,发送了FIN,这时客户端接到到了先前的ACK,也收到了对方的FIN,然后状态就由FIN_WAIT1转移到TIME_WAIT状态,然后发送ACK给对方。

  • 由FIN_WAIT2状态进入TIME_WAIT状态

这个就是一般情况,主动方在完成自身发起的主动关闭连接请求后,接收到对面的FIN,回复ACK后,状态发生转移。

总结一下:

section 1:主动方发送FIN请求关闭连接,这个时候FIN还没有到被动方,被动方此时也想着要关闭连接,也发了一个FIN报文

section1

section 2:主动方发送FIN给被动方后,被动方发现没有数据要传输了,这时就将FIN和ACK报文合成一包发给主动方,这时FIN_WAIT1就直接转移到TIME_WAIT状态了

section 2

section 3:也就是最正常的一种情况,主动方发起FIN,被动方此时还在传输数据,收到FIN先回复一个ACK,这时主动方状态转移到FIN_WAIT2,等被动方数据传输完毕,发送FIN报文到主动方,主动方回ACK并进入TIME状态

section 3

CLOSE_WAIT:

服务器接收到FIN后,发送ACK给客户端并进入该状态。我们可以理解为被动关闭的一方此时正在等待上层应用发出关闭连接的指令。上层处理完数据调用close关闭连接,这个时候服务器发送FIN.然后进入LAST_ACK状态。

LAST_ACK:

被动方发起关闭请求后,即发送FIN后,就进入该状态。收到客户端返回的ACK后返回到CLOSED状态度。

以上便是TCP状态转移的所有过程。

经典问题复现

Question 1

问: TIME_WAIT为什么需要等待2MSL才能变为CLOSED状态?什么是MSL?如果不想等怎么办?


1.MSL:Maximum Segment Lifetime指的是报文段在网络中的最大生存时间,任何报文段在网络中存在超过这个时间都将会被丢弃,在linux下该值被定义为30s,在RTOS下被定义为60s.

2.TIME_WAIT状态:说白了就是等待足够久的时间,一方面让网络上延迟未达到的数据可以自然消失,即被网络丢弃,那么再出现在这条链路上的数据一定是新连接生成的;另一方面就是等待最后一个ACK可以被被动方接受,确保连接正确关闭。

3.如果我们不想等2MSL怎么办呢?有两个方法:方法一:设置地址和端口重用,我们配置开启socket的属性SO_REUSEPORT和SO_REUSEADDR,这个时候模组做服务器就会在TIME_WAIT阶段可以继续使用原地址端口建立新连接;方法二:设置该socket的可选参数LINGER来帮助我们在连接close后等待可选时间发送RST强制断开连接即可,但这有风险,可能导致网络中未传输完毕的数据丢失。

Question 2

问:SYN_SENT如果等待超时会回到CLOSED状态,判定超时的依据是什么?

答:
1.RTT:数据从网络一端传输出去到接收确认所需要的的时间;RTO:重传超时时间,即超过这个时间还没有接收到确认包,就需要发起重传了。

2.客户端状态SYN_SENT需要接受服务器的确认和SYN来发生状态转换,但是由于网络原因,该SYN没有被服务器收到或者模块没收到服务器数据,就会开启重传定时器,等待RTO之后重新发送SYN报文,注意RTO的时间不是固定的,它会随着重传的次数翻倍,达到次数后还没有收到服务器的[SYN ACK],那么该状态结束返回到CLOSED状态。

3.Linux下握手信息默认重传5次,报文重传次数默认15次,LWIP中默认重传次数为7次

Question 3

问:请简述一下为什么需要三次握手和四次挥手?

答:
1.在RFC 793中对于三次握手的说明大概是:用于保证可靠性和流量控制的某些状态信息:包括socket(包含IP和端口信息);sequence number(用于保证可靠传输);window sizes(用于流量控制)

2.那么我们这里给出必须三次握手的原因:1).一个四元组确定一个唯一的连接,那么只有三次握手就可以让客户端有足够的的上下文来判断当前连接是否是历史连接,防止将历史连接初始化。2).序列号保证可靠传输,只有三次握手才能让通信双方正确交换保存序列号,达到可靠通信。

3.至于4次挥手 的原因就比较简单了:我们参考三次握手,那么至少也需要三次挥手,但是三次挥手不能解决网络中遗留的数据问题,即客户端收到ACK之后还需要等待服务器数据传输完毕之后发送FIN,那么就是将第二次过程拆分开来看,一句话就是为了保证网络中的数据都可以得到妥善处理后再关闭。

Question 4

问:如果三次握手或者四次挥手过程中的任何一包丢掉了,接下来会怎么样?

答:
1.同样先从三次握手说起:假如第一包握手信息丢失,此时客户端已经进入SYN_SENT状态,一个RTO内没有收到第二包握手信息就触发重传,5次重传后还没有收到则状态由SYN_SENT转移到CLOSED

2.假如第二包握手信息丢失:服务器此时已经进入SYN_RECVED状态,发送[SYN ACK]给客户端,报文丢失后会客户端没有收到确认触发第一次握手信息重传,同时服务器没有收到第三次握手信息触发第二包握手信息重传。同样在5次重传后状态转移为CLOSED。

3.假如第三包握手信息丢失:这个状态就比较特殊了,我们知道客户端在发送完第三包ACK之后就进入了ESTABLISH状态了,但这个时候服务器在等待这包ACK,没等到第三包握手即触发第二包重传,重传失败后发送RST断开连接。但是这期间客户端可是处于连接态的,客户端向服务器发送数据,由于全连接没有真正建立,数据就会进入不断重传的情况,直到到达数据最大重传次数后结束连接状态,由ESTABLISH转移到CLOSED状态。

4.至于4次挥手丢包情况可以参照三次握手分析,绕不过重传和状态转移。


记得公众号看一看呀!
微信公众号

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值