目录
上篇文章介绍了:传输层协议TCP报文的头部格式,TCP协议的“可靠”保证:确认应答机制、延迟重传机制,基于连接建立的“三次握手”、连接释放的“四次挥手”,以及可以提高传输效率的“滑动窗口”:传输层协议,TCP数据报(1)-CSDN博客。
接下来将继续介绍TCP协议的特性。
一、流量控制(基于接受方设为角度限制发送方的发送速率)
增加流量窗口的大小,可以提高传输的效率,但是窗口的大小不能无限制的增加。如果发送的太多,而接受方处理不过来,就会出现丢包了,即使再发送,也依旧会出现丢失,反而更浪费硬件资源。
所以,不如在接受方处理不过来之前就减缓发送的速度。让接受方影响发送方的速度。这样的机制叫做“流量控制”。
在TCP报文的头部有一个字段:16位窗口大小。
该字段在普通的报文中没有意义,但在ack报文中可以反馈给发送方接下来要发送的窗口设置成多少合适。接受方根据自己的接收缓存区剩余空间的大小,作为ack中窗口大小的报文。
1.窗口只能为64位?
不是,同时,在TCP首部的选项中,还有一个参数:窗口扩展大小。实际上真实的窗口可以设置为16位窗口大小*2^窗口扩展因子。
当返回的ack报文中的窗口大小为0时,发送端就停止发送。
2.什么时候恢复发送呢?
在发送方暂停发送的时候,发送方会周期性的给发送方发送“窗口探测包”,该包并不携带载荷,只是为了让接受方发送ack,如果返回的ack报文的窗口大小并不为0,则发送方可以继续发送数据。
二、拥塞控制(基于发送过程来限制发送方的发送速率)
如果接受方处理的速度很快,但是由于在发送过程中出现了问题,即使发送的很快,接受方也收不到数据。所以,这时就需要发送方控制发送的速度。
如果按照某窗口大小发送数据,若出现丢包,则减少窗口大小,若没丢包,则增大窗口大小。
(流量控制欲拥塞控制,谁计算的窗口大小更小,则按照窗口小的发送数据)
拥塞控制的窗口叫做拥塞窗口。
1.如何设计拥塞控制的窗口呢?
假设sstresh初始值为16,在拥塞窗口为24的时候,发生了丢包。
1.在开始的时候,①点开始慢启动算法,开始值比较小,为1。点①。
2.拥塞窗口没达到阈值之前,按照指数形式增加。1->2->4->8->16。点①~点②之间。
3.达到阈值后,在没出现丢包前,指数变成线性,+1。点②~点③之间。
4.丢包后,拥塞窗口置小值。重置窗口阈值,在该图中重置的窗口阈值,为出现丢包时的拥塞窗口的1/2。点④。
5.按照1-4的流程就行动态变化。
由于版本的更新,网络带宽、环境的不同。已经从Tache版本更新为Reno版本了。区别在于:在丢包之前,拥塞窗口设置为新的sstresh值,不会指数增加,而是线性增加。
三、延时应答
基于滑动窗口以及流量控制,通过延时应答ack 的方式,让接受方能处理更多的数据,从而将ack反馈的窗口大小变大一些。
1.延时应答应如何延时呢?
正常的数据,都有ack。通过采用每隔几个数据再返回ack的方式,不进可以减少ack的传输,也能减少开销。
但也不能无限制的等待数量足够,当延时时间到了,即使数量不够,也会返回ack 。
四、捎带应答
基于延时应答,引入捎带应答,目的是为了提高传输的效率。捎带应答,是将能够合并的数据进行合并。
ack延时应答,此时服务器进行响应也完成了。ack与应答的响应数据就会合并成一个数据。
ack本身不会携带数据,只是将报文中头部的ACK标志位设为1,设置确认序号以及窗口大小。这几个属性,不会与正常的response报文产生冲突。
很多时候,服务器与客户端之间属于长连接,有多次的请求与响应。在捎带应答的机制下,后续的请求与响应,都可能会触发捎带应答,将接下来要传输的数据与ack合二为一。
但是,如果下一个数据到来的时间,在延时应答的延时时间之内,就可以触发合并。
五、面向字节流
数据到达接受方后,读取非常灵活,代码无法区分当前的数据从哪到哪是一个完整的应用数据包。多个应用层数据包混淆不清,称为粘包。
粘包问题,不是TCP独有的问题,而是面向字节流都有的问题。所以就需要在发送的时候,“明确包之间的界线”。
1.如何“明确包之间的边界”?
(1)通过特殊符号,作为分隔符。但要确保当前使用的分隔符不会在正式的数据中出现。
(2)指定包的长度,比如在包开始的位置,加上一个特殊的空间也表示整个数据的长度。
对于这些问题,应该在设计应用层写实的时候设计好。
常见的应用层协议格式:xml、json、protobuffer都能处理粘包问题。
六、异常情况
当网络出现异常时,该如何处理?
1.其中一方进行崩溃
系统自动回收文件资源,进行“四次挥手”。即使进程退出了,但是TCP的连接周期比进程长,TCP的连接建立依旧存在。
2.有一方按照正常流程关机
“关机”,会将所有的进程终止,会触发“四次挥手”,但是如果断开连接完成的快,双方的连接信息都能删除。但是,如果完成的慢,也会给对方发出fin 报文,告诉对方我要断开连接了。对应端会返回ack和fin,但是不会有ack返回,对应端会重传fin,但是等待2MSL后还没有收到,就不会再重传了,单方面释放连接信息。
3.出现断电
如果是接受方断电了,发送端多次发送数据但是发现没有ack返回,TCP就会尝试与对方重新连接,进行“复位”连接。清除原来的TCP中的各种连接临时数据,重新开始。报头中的RET进行复位,如果重置后还收不到ack ,就会单方面放弃连接。
如果是发送方断电了,但是发送方是发送数据的一方,所以接受方就要区分,是发送方暂时没发,还是发送方挂了。接受方在一段时间后没有收到发送方发来的数据,就会触发“心跳包”来询问对方的情况。如果没有心跳,此时发送端也会尝试复位,没有ack,则单方面的释放连接。
TCP协议的心跳包心跳周期较长,所以在应用层自己设计心跳包。同时,“心跳包”是不带应用层数据的特殊数据包。
4.网线断开
3中双方的结合。
接受方会在一段时间后没有收到发送方发来的数据,就会触发“心跳包”来询问对方的情况。如果没有心跳,此时发送端也会尝试复位,没有ack,则单方面的释放连接。发送方会多次发送数据但是发现没有ack返回,TCP就会尝试与对方重新连接,进行“复位”连接。清除原来的TCP中的各种连接临时数据,重新开始。报头中的RET进行复位,如果重置后还收不到ack ,就会单方面放弃连接。
以上讲了10个机制,就是比较重要的关于TCP协议的相关内容。