TCP/IP——TCP的成块数据流、滑动窗口、慢启动、PUSH和URG

一、引言

我们看到TFTP使用了停止等待协议。数据发送方再发送下一个数据块之前需要等待接收对已发送数据的确认。TCP所使用的被称为滑动窗口协议的另一种形式的流量控制方法。该协议允许发送方再停止并等待确认前可以连续发送多个分组(但发送分组的总大小不能超过通告窗口)。由于发送方不必每发送一个分组就停下来等待确认,因此该协议可以加速数据的传输。

二、正常数据流

通常使用的“隔一个报文段确认”的策略(即每收到两个报文段发送一次确认,不是一定都是这样)。

当发送方发送一段数据后,接受发发送ACK,但通告其窗口大小为0,这说明接收方已收到所有数据,但这些数据都在接收方的TCP缓冲区,因为应用程序还没有机会读取这些数据。这时候发送发就会停止后续数据发送,等待接收方发送一个窗口更新。当接收方处理TCP缓冲区里的数据后,有闲置的空间时就会发送一个ACK(许多TCP实现在窗口大小增加了两个最大报文段长度或者最大可用窗口的50%时发送这个窗口更新,不会因为应用程序读取了10个字节,就通告窗口大小为10个字节),并通告窗口大小为缓冲区的大小。

三、滑动窗口

TCP有两个缓冲区,发送缓冲区和接收缓冲区,对应两个窗口,即发送窗口和接收窗口。即,滑动窗口即包括接收窗口,也包括发送窗口。通常所说的通告窗口,指的是接收窗口。
在这里插入图片描述
在这个图中,我们将字节从1至11进行标号。接收方通告的窗口称为提供的窗口,它覆盖了从第4字节到第9字节的区域,表明接收方已经确认了包括第3字节在内的数据,且通告窗口大小为6。我们知道窗口大小是与确认序号相对应的。发送方计算它的可用窗口,该窗口表明多少数据可以立即被发送。当接收方确认数据后,这个滑动窗口不时地向右移动。窗口两个边沿的相对运动增加或减少了窗口的大小。

称窗口左边沿向右边沿靠近为窗口合拢。这种象限发生在数据被发送和确认时。

在这里插入图片描述
当窗口右边沿向右移动时将允许发送更多的数据,我们称之为窗口张开。这种现象发生在另一端的接收进程读取已经确认的数据并释放了TCP的接收缓存时。
当右边沿向左移动时,我们称之为窗口收缩。RFC强烈建议不要使用这种方式。

滑动窗口协议通过窗口的更新控制数据传输,窗口的更新有三种情况:
1.窗口合拢:窗口的左端向右移动,在发送端表示窗口数据被发送,在接端则表示数据被确认;
2. 窗口张开:窗口的右端向右移动,表示接收端应用层进程读取经确认的数据从而释放缓冲区;
3. 窗口收缩:窗口的右端向左移动,RFC强烈建议不要使用这种方式。
若窗口左端到达右端,称其为零窗口,表示一种缓冲区的饱和状态。
TCP接收端如果窗口宽度为零,在处理完数据释放缓冲后需要再次向发送端提供当前的窗口大小信息。(窗口更新报文)

窗口的大小影响着TCP的性能,对主机的吞吐量影响很大,服务器需要更大的窗口。

快的发送方和慢的接收方

一个快的发送方和一个慢的接收方,很容易导致接收方的接收窗口(通告窗口)为0。这时发送方将无法再继续发送数据。

接收窗口为0时,随着应用程序将数据从接收方缓存中读取出来,接收窗口的可用大小不断增长,这时接收方会发送一个窗口更新包给发送端,告诉其当前的接收窗口大小(通告窗口),让其能够继续发送数据。但更新包不是在接收窗口一有可用空间就向对端发送,而是等到接收窗口的可用大小增大到整个接收窗口的50%或者达到2个报文段(MSS)大小的时候,才发送窗口更新包。之所以不一有空闲就发送窗口更新包,是为了避免糊涂窗口综合症。

窗口更新报文是接收端用于通知发送方当前自己接收窗口的大小。但该报文可能会丢失,由于针对该报文不启用超时定时器,无法进行超时重传,所以无法保证该报文被对端接收到。如果对端接收不到对方通告窗口大小,就不会继续发送数据。通过坚持定时器来解决该问题。

四、慢启动

发送方一开始便向网络发送多个报文段,直至达到接收方通告的窗口大小为主。当发送方和接收方处于同一个局域网时,这种方式是可以的。但是如果在发送方和接收方之间存在多个路由器和速率较慢的链路时,就有可能出现一些问题。一些中间路由器必须缓存分组并有可能耗尽存储器的空间。
TCP需要支持一种被称为“慢启动”的算法(不允许开始一下子就发送通告窗口的大小,需要缓慢增加速率)。该算法通过观察到新分组进入网络的速率应该与另一端返回确认的速率相同而进行工作。
慢启动:发送方通过使用“拥塞窗口”实现慢启动,初始大小为1个报文段,此后每收到一个ACK,窗口大小就增加一个报文段,取拥塞窗口和对方通告窗口之间的最小值为发送上限(累积发送但未确认的MSS个数)。

慢启动通过一个拥塞窗口(cwnd)来实现,发送端能够发送累积但未确认的报文段的个数为cwnd和对端通告窗口大小中的小者。拥塞窗口是发送方使用的流量控制,而通告窗口则是接收方使用的流量控制。

慢启动为发送方的TCP增加了另一个窗口:拥塞窗口

拥塞窗口

拥塞窗口(congestion window),记为cwnd。当与另一个网络的主机建立TCP连接时,拥塞窗口被初始化为1个报文段(1个报文段即为一个MSS,MSS=MTU-40)。每收到一个ACK,拥塞窗口就增加一个报文段(cwnd以字节为单位,但是慢启动以报文段大小为单位进行增加)。发送方取拥塞窗口与通告窗口中的最小值作为发送上限。拥塞窗口发送发使用的流量控制,而通告窗口则是接收方使用的流量控制。

发送方开始时发送一个报文段,然后等待ACK。当收到该ACK时,拥塞窗口从1增加为2,即可以发送两个报文段。当收到这两个报文段的ACK时,拥塞窗口增加为4.(当然这是一种理想的增长,因为发送两个报文段,接收方不一定会发回2个ACK,一般只会发送回一个ACK来确认这两个包已经收到,有时候哪怕拥塞窗口为4了,也不一定下一次就会发送4个报文段,也可以只发送3个。)这是一种指数增加的关系。

在某些点上可能到达了互联网的容量,于是中间路由器开始丢弃分组。这就通知发送方它的拥塞窗口开得过大。

发送一个分组的时间

通常发送一个分组的时间取决于两个因素:传播延时(在网线里面传播的延时)和发送延时(10M以太网和10G以太网)。对于一个给定的两个节点之间的通路,传播时延一般都是固定的,而发送时延则取决于分组的大小。在速率较慢的情况下发送时延起主要作用,而在千兆比特速率下传播时延则占主要地位

五、慢启动的例子

慢启动中,cwnd为指数增长,而非线性。
注意: 这是城是每收到一个ACK,就增加一个报文段(MSS),是一种指数增长的关系,而不是线性增长。
在这里插入图片描述
对发送端:

第一次,发 1 个MSS。

等待这1个MSS的ACK,并收到 1 个ACK。由于原来可以发1个MSS,现在又增加了一个。因此,第二次可以发2个MSS。

第二次,发 2 个MSS。

等待这2个MSS的ACK, 并收到2个MSS的ACK。由于原来有2个MSS,现在收到2个ACK,又可以增加2个MSS。因此,下一次可以发送2+2=4个MSS。

第三次,发送4个MSS。

注意,这中间拥塞窗口cwnd不是跳跃增长的(如,1,2,4,8,16),而是每收到一个ACK之后,都会增长1,而不是等所有的ACK都到了之后,一次性跳跃增长。(见上图中的cwnd值:1,2,3,4,5)。而且,只要能发送数据(当前已发送的数据量小于对端的通告窗口和cwnd中的小者),就会发送数据。实际上,并不存在所谓的“第二次必须一次性发2个MSS”、“第三次一次性发4个MSS”的说法。整个发送过程和接收ACK的过程,都是连续的,而非集中和跳跃的。

对于发送端(左侧):

1). 初始化cwnd为1个报文段;发送了一个报文段;

2). 收到了ACK。这时,cwnd为2了,可以发送2个报文段(MSS)的大小(可发送多少个报文段,取cwnd和对端通告窗口大小中的小者,注意单位不一样),也就是说,可以累积发送但未确认的报文段这时是2个。

3). 然后发送了2个报文段(报文段3和4)。

4). 收到了一个ACK,这时cwnd变为了3.已发送但未收到确认的报文段为1个(上次发了2个报文段,这里收到了一个回复ACK)。这时,总共可以发送的报文段(累积未确认)个数为3(cwnd和对端通告窗口中的小者)。因此接下来,又发送了3-1=2个报文段。

注意:

发送方将拥塞窗口大小(报文段数目*报文段大小)与通告窗口大小相比较,取其小者作为对端的窗口大小,用于限制发送方可以累积发送但未确认的报文段数量。
拥塞窗口发送发使用的流量控制,而通告窗口则是接收方使用的流量控制。

1个报文段的大小,是对方通告的MMS值的大小,与本地的MTU值的比较,取小者做为一个报文段的大小。

传送通道的容量=带宽时延乘积,即带宽x时延(RTT)。为理想的稳定状态下,传送通道上报文段的大小,接收端的通告窗口必须不小于这个数目。

六、PUSH和URG标志

PUSH标识,用于在接收方收到该数据包之后,立即交于上层的应用进程。发送方使用该标志通知接收方将所收到的数据全部提交给接收进程。这里的数据包括与 PUSH一起传送的数据以及接收方TCP已经为接收进程收到的其他数据(该次随PUSH标志一起收到的数据和之前收到的数据)。

PSH(急迫位): 在一个交互程序中,当客户发送一个命令给服务器时,它设置P U S H标志并停下来等待服务器的响应。通过允许客户应用程序通知其T C P设置P U S H标志,客户进程通知T C P在向服务器发送一个报文段时不要因等待额外数据而使已提交数据在缓存中滞留。类似地,当服务器的T C P接收到一个设置了P U S H标志的报文段时,它需要立即将这些数据(包括以前存中滞留的数据)递交给服务器进程而不能等待判断是否还会有额外的数据到达。 PSH=1,只对接收方的接收缓冲区起作用,发送方通过使用PUSH位来通知接收方将所有收到的数据立即提交给服务器进程,而不需要等待额外数据(将缓存填满)而让数据在缓存中停留!这里所说的数据包括与此PUSH包一起传输的数据以及之前就为该进程传输过来的数据(滞留在缓存中的数据)。

URG(紧急位): 急指针是一个正的偏移量,和序号字段中的值相加表示紧急数据最后一个字节的序号。T C P的紧急方式是发送端向另一端发送紧急数据的一种方式。紧急指针指向包内数据段的某个字节。

可以通过设置 T C P首部中的两个字段来发出这种从一端到另一端的紧急数据已经被放置在数据流中的通知。 U R G比特被置1,并且一个 1 6b i t的紧急指针被置为一个正的偏移量,该偏移量必须与 T C P首部中的序号字段相加,以便得出紧急数据的最后一个字节的序号。

T C P本身对紧急数据知之甚少。没有办法指明紧急数据从数据流的何处开始。 T C P通过连接传送的唯一信息就是紧急方式已经开始(T C P首部中的 U R G比特)和指向紧急数据最后一个字节的指针。其他的事情留给应用程序去处理。

猜你喜欢

转载自blog.csdn.net/weixin_44233369/article/details/87908816