咱们大部分业务都创建在TCP之上,并且都通过框架层层的封装,让人很难看清其中的奥妙。但在和外部机构(如银行)交互的过程当中,有不少采用的是自研的基于TCP的协议。此时没法依赖框架,咱们就只能本身去编写基于TCP的代码,若是充分了解TCP的种种特性,和他们对接起来就会事半功倍。相信你们在开发TCP代码的过程当中,也确定了解了粘包、长短链接这些概念。粘包和TCP窗口有关、长短链接性能优劣和TCP传输策略有关。这篇文章着重介绍TCP窗口。程序员
TCP发送窗口由slide_window(滑动窗口)、congestion_window(拥塞窗口)二者决定,代码以下(4.4BSD-Lite2):面试
上面的snd_wnd、snd_una、snd_nxt三个字段组成了滑动窗口。 以下图所示算法
发送端窗口随时间滑动图(不考虑重传)例以下所示:
图2 发送窗口随时间滑动图
(1)咱们一共须要发送900字节数据。可发送数据为1-500字节,还没有发送数据。假设首先发送400字节的数据。
(2)发送了400字节后,对端返回一个ack表示收到200序号以内的数据且窗口通告为500。因而如图示,窗口向前滑动了200字节。当前已发送未确认字节序号为200-400,可发送字节序号为401-700,假设在此还没有发送数据。
(3)对端返回一个ack表示收到400序号内的数据且窗口通告为400。因而如图示,窗口向前滑动了200字节。已确认数据序号为1-400,可发送数据为401-800。缓存
snd_wnd此字段主要由接收端的窗口通告决定,接收端窗口通告由当前接收端剩余多少空闲的剩余缓存决定。以下图所示:服务器
图3 接收窗口通告网络
(1)发送端:写入2KB的数据[seq=0]。
(2)接收端:收到数据,初始化接收端缓冲区4K,写入后还剩2K,因而通告ack[seq=2048,win=2048]。
(3)发送端:接收到窗口通告为2048,因而最多只能写入2K的数据,将2K数据写入[seq=2048]。
(4)接收端:应用层还没有消费缓冲区。接收到2K数据后,缓冲区满。因而通告窗口为0,返回ack[seq=4096,win=0]。
(5)发送端:因为发送窗口为0,不能发送任何数据。此时发送端就须要定时的发送0字节的数据去探测接收端窗口。所需的定时器即为持续定时器(TCPT_PERSIST)。
(6)发送端:发送0字节的探测数据。
(7)接收端:缓冲区满,窗口通告为0,ack[seq=4096,win=0]。
(8)发送端:继续发送0字节的探测数据。
(9)接收端:缓冲区被应用层消费了2K,缓冲区可用字节为2K,通告窗口为2048,ack[seq=4096,win=2048]。
(10)发送端:继续写入1K的数据。框架
TCP用拥塞窗口(cwnd)来进行拥塞控制,主要利用了慢启动、拥塞避免、快速重传和快速恢复这四个算法。ssh
拥塞避免算法和慢启动算法是两个目的不一样、独立的算法。慢启动的目的是:防止一开始速率过快,致使耗尽中间路由器存储空间,从而严重下降TCP链接的吞吐量。拥塞避免的目的是:当拥塞发生时,下降网络的传输速率。这能够经过调用慢启动的动做来下降网络的传输速率。因此在实际中这两个算法一般在一块儿实现。tcp
下述代码描述的是慢启动的过程(4.4BSD-Lite2)。
其将win置为现有窗口的大小,同时慢启动门限tp->snd_ssthresh设置为现有窗口大小的一半。snd_cwnd(拥塞窗口)被设定为只能容纳一个报文t_maxseg),这样就强迫TCP执行慢启动。以后拥塞窗口会先以指数形式增加,达到慢启动门限snd_ssthressh以后,再线性增加。分布式
线性增加的过程便是拥塞避免算法。
此过程如如下代码注释所示(4.4BSD-Lite2):
慢启动图例:
图中Cwnd指数增加的阶段,即从1到ssthresh时间段是过程是慢启动。
图中Cwnd线性增加的阶段,即从ssthresh到max的时间段是拥塞避免的过程。
值得注意的是,TCP链接刚创建时刻也会有慢启动的过程。若是用的是短链接(即发送一个请求以后即抛弃此链接)且发送数据较少的话,大部分时间都耗在了慢启动上面,并无充分的利用带宽。再加上创建链接所须要三次握手的消耗,致使短链接的效率要远低于长链接。
通过上述讨论,可知TCP窗口的大小取决于当前的网络情况、对端的缓冲大小等等因素,TCP将这些都从底层屏蔽。开发者没法从应用层获取这些信息。这就意味着,当你在接收TCP数据流的时候没法知道当前接收了有多少数据流,数据可能在任意一个比特位(seq)上。这就是所谓的"粘包"问题。开发者必须当心的组织帧格式来解决"粘包"。
精心整理 | 2017下半年文章目录
分布式之消息队列复习精讲(下)
面试之链表问题集锦(下)
数学分析告诉咱们什么?
C++中的类型转换
Stack Overflow 10个关于程序员有趣的调查
码农有道,为您提供通俗易懂的技术文章,让技术变的更简单!