天天看点

(五)深入浅出TCPIP之TCP流量控制

TCP流量控制

   我们都知道TCP是一种可靠的,面向连接的传输层协议。我们总是希望TCP能够传输的数据越快越好。如果存在这样一种情况,发送方数据发送的非常快,而且接收方耗尽自己的资源也根本来不及接收,那这些多余的数据就会被丢弃,这就违背了TCP可靠的宗旨了。

   所以就需要引入一种流量控制的手段:让发送方不要发送太快,既让接收方能够顺利接收数据,而且也不会造成网络链路的阻塞。 

滑动窗口

为了让发送方不要发送的太快。那就让接收方控制发送方的数据大小,每次应答的时候通知发送方自己还剩多少空间可以接收数据。那么滑动窗口类似一个窗口,是用来告诉发送方可以发送数据的大小。也可以说是窗口标记了接收方缓冲区的大小。窗口大小也就表示一次能发送多少数据量,而且这个窗口可以滑动,滑动窗口因此得名。

固定窗口和滑动窗口

我们可以看下面一张图来分析一下固定大小窗口有什么问题。

   这里我们可以看到假设窗口大小是1,也是就每次只能发送一个数据只有接收方对这个数据进行确认了以后才能发送第2个数据。我们可以看到发送每发送一个数据接收方就要给发送方一个ACK对这个数据进行确认。只有接收到了这个确认数据以后发送方才能传输下个数据。这样我们考虑一下如果说窗口过小,那么当传输比较大的数据的时候需要不停的对数据进行确认,这个时候就会造成很大的延迟。如果说窗口大小定义的过大。我们假设发送方一次发送100个数据,但接收方只能处理50个数据。这样每次都会只对这50个数据进行确认。发送方下一次还是发送100个数据,但是接收方还是只能处理50个数据。这样就避免不了不必要的数据来拥塞我们的链路。所以我们就引入了滑动窗口机制,窗口大小并不是固定的而是根据我们之间的链路的带宽的大小,这个时候链路是否拥塞,接收方是否能处理这么多数据了。

我们看看滑动窗口是如何工作的,我们看下面几张图

首先是第一次发送数据,这个时候的窗口的大小是根据链路带宽的大小决定的。我们假设这个时候窗口大小是3,这个时候接收方收到数据以后会对数据进行确认告诉发送方我下次希望收到的数据是多少。这里我们看到接收方发送的ACK = 3(这是发送方发送序列2的回答确认,下一次接收方期望接收的是3序列信号)。这个时候发送方收到这个数据以后就知道第一次发送的3个数据对方只接收了2个。就知道第3个数据对方没有收到。下次在发送的时候就从第3个数据开始发,这时候窗口大小就变成了2

这个时候发送方发送2个数据

看到接收方发送的ACK是5就表示它下一次希望收到的数据是5,发送方就知道我刚才发送的2个数据对方接收了,这个时候开始发送第5个数据。

这就是滑动窗口的工作机制,当链路变好了或者变差了,这个窗口还会发生变化,并不是第一次协商好了以后就永远不变了。

如何告知发送方窗口大小

如何通知发送方窗口大小呢?难道要重新发送一包数据告诉对方吗,这显然是不合理的。可以巧妙的使用确认应答包。需要在三次握手时候,就告知对方。在原来的确认应答策略中,每一次发送数据,都需要Ack应答,在接收到Ack之后才会发送下一个数据段,发送方没有接收到Ack应答呢?这样做的方式效率实在太低。使用了滑动窗口,可以多次发送数据,只要不要超过对方窗口大小。这样就大大提高了效率。

滑动窗口细节

  1. 接收方将自己能够接收的缓冲区大小是在TCP首部中的“窗口大小”字段表示的,通过Ack通知发送方。
  2. 窗口大小是发送方可以发送数据的,也就是说可以不需要Ack应答,可以发送多次数据,前提发送总数据量不要超过窗口大小。
  3. 窗口大小大说明网络的吞吐率高
  4. 操作系统内核维护了一块接收缓冲区,只有Ack应答之后的数据才能从缓冲区中删除。
  5. 接收方一旦发现自己的缓冲区快满了,就会通知对方自己的窗口为更小的值。
  6. 如果接收方发现自己的缓冲区满了,就会将窗口的大小设置为0,此时发送方将不再发送数据,但是需要定期发送一个窗口探测数据段,使接收方把窗口大小告诉发送方 。(针对这一点重点说明下为什么需要定期发送窗口探针?可以想象下,如果接收方缓冲区满了,然后通过Ack告知发送方窗口大小为0。发送方从此不会发送数据给接收方,接收方也没办法告知对方自己缓冲区可以接收数据,就会出现“卡死”的情况)                    

流量控制是端到端的控制,例如A通过网络给B发数据,A发送的太快导致B没法接收(B缓冲窗口过小或者处理过慢),这时候的控制就是流量控制,原理是通过滑动窗口的大小改变来实现。

实例

A 向 B 发送数据。在连接建立时,B 告诉 A:“我的接收窗口 rwnd = 400(字节)。注意:图中的箭头上面大写的ACK表示首部中的确认位ACK,小写ack表示确认字段的值。

上面的过程是这样的:

  1. A发送了数据序号1至100,还能发送300字节
  2. A发送了数据序号101至200,还能发送200字节
  3. A发送了数据序号201至300,但是丢失了数据
  4. B发送了ACK,同时通知A,允许A发送序号201至500,300字节
  5. A发送了数据序号301至400,还能发送100字节
  6. A发送了数据序号401至500,不能发送数据了
  7. A超时重传旧的数据,但不能发送新数据
  8. B发送了ACK,同时通知A,允许A发送序号501至600,100字节
  9. A发送了数据序号501至600,不能发送数据了
  10. B发送了ACK,同时通知A,不允许A发送数据

注意流量控制和拥塞控制的区别:

流量控制是指点对点通信的控制,做的是抑制发送端发送数据的速率,便于接收端来得及接收。

拥塞控制是防止过多的数据注入网络中,使得网络中路由器或链路不致过载,有一个前提是,网络能够承受现有的网络负荷,是一个全局性过程;

连环发问

1、TCP有几个滑动窗口?

 这里说明下,由于TCP/IP支持全双工传输,因此通信的双方都拥有两个滑动窗口,一个用于接受数据,称之为接收窗口;一个用于发送数据,称之为拥塞窗口(即发送窗口)。指出接受窗口大小的通知我们称之为窗口通告。

2、接收窗口的大小固定吗?

在早期的TCP协议中,接受接受窗口的大小确实是固定的,不过随着网络的快速发展,固定大小的窗口太不灵活了,成为TCP性能瓶颈之一,也就是说,在现在的TCP协议中,接受窗口的大小是根据某种算法动态调整的。

3、接受窗口越大越好吗?

接受窗口如果太小的话,显然这是不行的,这会严重浪费链路利用率,增加丢包率。那是否越大越好呢?答否,当接收窗口达到某个值的时候,再增大的话也不怎么会减少丢包率的了,而且还会更加消耗内存。所以接收窗口的大小必须根据网络环境以及发送发的的拥塞窗口来动态调整。