TCP协议学习总结(中)

很多人都说TCP协议是一个十分复杂的协议,在学习当中,我对协议每一个问题都分解学习后,每一个分解我都能体会和理解它的要点,并不难理解。但我把这些拆分的细节合并后,确认感觉这样一个协议相对“臃肿”但又好像不得不这样做的感觉。也写过那么多年代码,我也十分理解这种“分布”和“一致”的协调,就好像CAP理论一样,更关键的是许多的CAP选择都是依赖于TCP这样可靠的协议之上,可想而知它“可靠性”的重中之中,我也看到了根基扎实稳重的重要性。当然技术还在不断进步,协议的完善和优化从没有停止,无论如何,学习还得继续。

TCP的交互数据流

1、交互式输入

有些场景比如聊天,对信息交互的时效性非常敏感,又还比如远程操作,我们在本地点击一下鼠标的远程操作,需要被操作设备非常及时的响应,这样一些场景就是交互式输入。

TCP协议学习总结(中)

交互式输入是场景需要之一,它是牺牲了网络利用率而满足了时间的一种选择,试想一下如果客户端每一个小小的动作(如点击ENTER键产生1个字节)就要带着20个字节的TCP头部以及20个自己的IP头部,一共41个字节在网络上跑,如果每种交互都是这样的话,网络的利用率大大降低,所以这种情况更多适用于局域网内。而且在这种交互式交互时还可以看到TCP头部的PSH标识被设置了,它的意思是赶紧把数据交给应用程序,而不是先放缓冲区。

客户端的实时推送请求以及服务端的及时响应确实能保证了“实时交互”的效果,但这里会隐藏了一个客户端对服务端数据回显确认报文(ACK)的一个延迟发送。我们都知道TCP交互是一个可靠的协议,所以对数据的接收和确认是必然的要做的事情,我觉得既然客户端已经得到了服务端的及时响应,对服务端数据的确认响应已经不需要那么及时了。好好地在这一个点上的优化可以节省了网络的不必要浪费。

TCP协议学习总结(中)

通常TCP在接收到数据时并不会立刻发送ACK,相反,它推迟发送,以便将ACK与需要沿该方向发送的数据一起发送(有时这种现象为数据捎带ACK)。绝大多数实现采用的时延为200ms,也就是说,TCP将以最大200ms的时延等待是否有数据一起发送,这样做就节省了不必要的网络开销,从这一点看,TCP协议也是想绝了,毕竟资源珍贵,容不得半丁点的浪费。

2、Nagle算法

虽然交互式输入更多适用在局域网,但广域网就不能用这是不可能的,实时交互式这种场景会产生许多的(微)小分组,例如41字节中的真正数据才1字节。这确实会增加广域网拥塞的可能性。但是“道高一尺,魔高一丈”,一种简单和好的方法应运而生,那就是Nagle算法。该算法要求一个TCP连接上最多只有一个未被确认的未完成的小分组,在该分组的确认到达之前不能发送其它的小分组,相反,TCP收集这些少量的分组,并在确认到来时以一个分组的方式发出去。该算法的优越之处在于它是自适应的:确认到达得越快,数据也就发送得越快。而在希望减少微小分组数目的低速广域网上则会发送更少的分组。

 

TCP协议学习总结(中)

从上图可以看到,因为Nagle算法的生效,所以在“按键”输出后没有等到服务端响应确认前的后续4次数据输入都无法发送,而是等到服务端确认ACK到达后一起打包发送。有一点需要注意的是,这里的输入假设都是小分组输入,并没有很大的数据输入(不超过MSS)。Nagle算法算是在广域网上做了一个这种的选择,对数据交互实时性的影响不会太大,而又对互联网做了一层较好的保护,让交互的效果自适应网络的状态。

TCP的成块数据流

 1、滑动窗口

交互式输入我觉得从综合场景来看,相对少数。大部分情况下,大块的数据流交互才是“王道”,这里并不是说我们平时的应用交互就不需要实时,只不过这个“实时”是相对的,在数据量大的情况下如何才是最佳的交互体验,具体问题具体分析才是王道。在TCP头部中我们知道有一个叫做“16位窗口大小”的属性,这个窗口在上一节也介绍过相当于数据接收的“缓存区”,数据交互的双方(无论主动还是被动)都会维护着自己的一个窗口,应用程序没有消费数据之前都是停留在这个缓冲区中。所以,窗口可以看做TCP交互限流的一个关键所在,如果窗口爆满的一方是无法接收数据了,发送方也只能暂停发送,等待对方窗口的空闲才继续发送。毕竟双方应用程序处理数据的速度不一或者网络网速的客观影响,很难确认完美的状态,所以很需要一个像窗口一样的概念去维护双方之间的一个传送速度。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyjdpw.html