TCP核心机制
前一篇文章 JavaEE: 深入探索TCP网络编程的奇妙世界(四)
书接上文~
TCP核心机制六: 拥塞控制
为什么要有拥塞控制?
虽然有了TCP滑动窗口这个大杀器,能够高效可靠的发送大量数据,但是如果在刚开始阶段就发送大量的数据,仍然可能引发问题.
因为网络上有很多的计算机,可能当前的网络状态就已经比较拥堵,在不清楚当前网络的状态下,贸然发送大量的数据,可能导致雪上加霜.
动态调整的拥塞控制
流量控制可以使用接收方接收缓冲区剩余空间来进行衡量.
但是拥塞控制就比较复杂了.需要考虑中间节点的情况.比如:
- 中间的节点非常多.
- 每次传输的数据,走的路线还都不一样.
- 中间哪个节点遇到瓶颈了,都不好说.
- 中间节点传输数据不止有你A的数据,还有其他设备的数据.
虽然问题看起来更复杂了,但是不打紧,聪明的程序员总有办法.
我们可以通过"做实验"的方式,来找到一个合适的发送速度.
- 先按照一个比较小的速度,发送数据.
- 数据非常畅通,没有丢包,说明在网络上传输数据整体上是比较通畅的,此时就可以加快传输数据的速度~
- 增大到一定的速度之后,发现丢包了,说明网络上可能存在拥堵了,此时就可以减慢传输数据的速度.
- 减速之后,发现又不丢包了,继续再加速.
- 加速之后发现又丢包了,继续减速.
发送速度是会一直持续的动态变化的~
毕竟网络环境也是一直变化的.
流量控制,会限制发送窗口
拥塞控制,也会限制发送窗口
这两个机制,会同时起作用,最终实际的发送窗口大小,取决于上述两个机制得到的发送窗口的较小值~
拥塞控制中,窗口大小具体的变化过程
- 刚开始传输数据,拥塞窗口会非常小,用一个很小的速度来发送数据
当前网络是否拥堵?未知.
刚启动的时候,发数据的速度很慢~ - 不丢包,增大窗口大小(指数增长)
增长速度特别快,短时间内达到很大的窗口大小.
- 增长到一定程度,达到某个指定的阈值,此时,即使没丢包,也会停止指数增删,变成线性增长.
不至于太快的进入到丢包的节奏
- 线性增长,也会持续地使发送速度越来越快,达到某个情况下,就会出现丢包.
一旦出现丢包,接下来就需要减少发送的速度,减小窗口大小.
此时有以下两种出来方式:- 经典的方案,回归到开始非常小的初始值,之后指数增长,线性增长~
- 现在的方案,回归到新的阈值上,线性增长(以后都不会指数增长了).
拥塞控制,归根结底是TCP协议想尽可能快的把数据传输给对方,但是又要避免给网络造成太大压力的折中方案.
流量控制和拥塞控制,实际上都是在对"可靠传输"进行补充~
TCP核心机制七: 延时应答
如果接收数据的主机立刻返回ACK应答,这时候返回的窗口可能比较小.
- 假设接收端缓冲区为1M,一次收到了500K的数据,如果立刻应答,返回的窗口就是500K.
- 但实际上可能处理端处理的速度很快,10ms之内就把500K数据从缓冲区消费掉了.
- 在这种情况下,接收端处理还远没有达到自己的极限,即使窗口再放大一些,也能处理过来.
- 如果接收端稍微等一会再应答,比如等待200ms再应答,那么这个时候返回的窗口大小就是1M.
一定要记得,窗口越大,网络吞吐量就越大,传输效率就越高,我们的目标是在保证网络不拥塞的情况下尽量提高传输效率~
所有的包都可以延迟应答吗?肯定也不是~
- 数量限制: 每隔N个包就应答一次.
- 时间限制: 超过最大延迟时间就应答一次.
具体的数量和超时时间,不同的操作系统有不同的差异,一般N取2,超时时间取200ms.
TCP核心机制八: 捎带应答
捎带应答是在延时应答的基础上,引入的提升效率的机制,它可以把返回的业务数据,和ACK两者合二为一.
在实际网络通信中,大部分的情况,都是"一问一答"这样的形式~
ack是内核返回的,是收到请求之后,立即就返回ack.
响应,则是应用程序返回的.在代码中,根据请求计算得到响应,再把响应写回到客户端.
正常情况下,ack和响应,是不同的时机返回的,无法合并.
但是,ack涉及到"延时应答".
延时应答就会使ack返回的时间,被往后拖.
这样一延时,就可能赶上接下来要发送响应数据的操作了.于是就可以在发送响应的时候,把刚才ack的信息也带上.
本身ack报文,不需要载荷,ack报文主要设置以下内容
- ack这一位为1
设置窗口大小的值,设置确认序号…相应数据主要是设置载荷,和ack不冲突.
这俩是可以共存的~
四次挥手,也涉及到类似的情况.
延时应答,捎带应答,都是TCP提升性能的机制.
TCP之所以复杂,不仅仅在考虑可靠传输,还要考虑在可靠传输的基础上,尽可能的提高效率~
下一篇文章 JavaEE: 深入探索TCP网络编程的奇妙世界(六)