TCP协议的核心机制
一:确认应答机制
对于TCP协议来说,要解决的一个很重要的问题,就是可靠传输
可靠传输,不是指发送方能够100%的把数据发送给接收方,而是尽可能.
尤其是让发送方知道,接收方是否收到.
举个例子:
我去吃麻辣烫,和老板说: 少加辣椒,
此时老板就会回应: 好的好的(这样用于"应答的数据,就成为"应答报文")
确认应答机制,核心就是靠对方给你一个应答.
但如果批量发送数据的时候,可能会出现一些问题,
因为网络中传输的数据可能会出现"后发先至"的情况(后发先至是网络通信中,客观存在的,改变不了)
比如:
(考虑鸡腿卖完了的情况)
我向老板说:少加辣椒,加个鸡腿
如果老板先听到"加个鸡腿",回复"不行"
然后听到"少加辣椒",回复"好的".
此时明显是错的.
那么就需要能够对要传输的数据进行编号,并且让应答报文的编号和发送数据的编号能够对应起来,即使出现后发先至,也不会影响传输意思的理解.
我: 1) 少加辣椒
2)加个鸡腿
老板:针对1):好的好的
针对2):不行
但实际上,真实的TCP的序号不是按照"一条两条"方式来编号的,而是按照以字节为单位进行编号的,每个字节会分配一个编号.
比如:传输的数据含有1000个字节,编号可能就是1-1000,但发送方的报头中,序号中的数值就是载荷部分的第一个字节的编号:1;发送方的报头中,序号字段有效,而确认序号字段是无效的;
而接收方的确认序号就是数据最后一个字节的编号+1;接收方返回的ack,"确认序号"有效,"序号"字段是无效的.
也就是1001.
1.2:超时重传
确认应答机制:讨论的是发送方能否把数据发给接收方,发送成功,接收方就会给一个应答,没发送成功,接收方就没有应答,没发送成功就称为丢包了.
但如果发送成功,但接收方的应答报文出现丢包的情况,导致发送方接收不到应答呢?
超时重传机制就是应对网络中出现丢包情况(发送方丢,接收方丢)时的一种策略
超时:发送方发送数据之后,会等待一定的时间,如果等待时间超过某个"阈值",还没收到ACK,就认为是出现丢包了.出现丢包,就会重传 ,把刚才发送的数据在发送一遍.
发送方等待一定时间后,没有收到ACK,(ack回应晚了,超过了等待时间,也认为是没有收到ACK)就会触发超时重传机制.
ack丢了,也会触发超时重传机制,不就发送了两份重复的数据了吗??
想一个场景:对于转账这样的操作,触发重传就引起重复转账
所以在应用层一定要保证应用程序在read的时候不能读到重复的数据.
其实TCP接收方会根据序号字段进行去重.
接收缓冲区
接收方的操作系统内核中,存在一个数据结构,“接收缓冲区”,类似于PriorityBlockingQueue.
如何知道队列中,之前存在过?
接收缓冲区,除了去重之外,还有一个很重要的功能,针对收到的数据进行排序.
A按照1 2 3 4 这样的顺序write ,B这边read 的时候,也是按照1 2 3 4 read出来
虽然网络传输的中间过程可能是后发先至,可能是乱序的,但在接收缓冲区里,会对收到的数据先排个序,让序号小的,在前面,序号大的,在后面.
超时重传时间
丢包,本身就是一个概率性事件:
假设,网络丢包率是0.1 (已经很大了)
触发一个重传,如果重传的包也丢了,概率就是 0.1*0.1 =0.01,
也就是两次传输数据都丢包的概率是0.01,也就是0.99的概率是至少传输成功一次.
随着重传的次数增加,成功一次概率继续变大,反之,如果连续重传几次,都丢包,说明当前本身丢包的概率就非常大了,网络应该是存在严重故障了.
超时时间,不是固定的,而是随着重传次数的增加,会变得越来越长.
假设,第一次传输数据,等待50ms ,触发重传
重传之后,可能就会等待100ms,没收到ACK,触发重传
重传之后,可能就会等待150ms…
超时时间间隔就会越来越长(不一定是线性增长,具体怎么增长,取决于系统的具体实现)
也就是重传的效率越来越低.
大概率重传一次就会成功,如果需要重传多次,大概率就是网络故障了,能成功的概率就比较低了;如果重传的越来越快,但成功的概率比较低,是非常浪费系统资源的.
重置连接
如果网络上确实出现严重故障了,重传若干次,还是不成功,达到一定次数阈值,就会尝试"重置连接".
网络出现严重故障,RST报文也无法顺利完成,此时重置也失败了,就只能断开连接了.(释放掉保存对方信息的数据结构)
(重置连接可能有用)
TCP的可靠传输,全靠确认应答机制和超时重传机制.