2017年2月

TCP流量控制和拥塞控制

流量控制

利用窗口滑动窗口控制流量

流量控制

  • 死锁问题
  • 提升传输效率 - Nagle算法(缓存应用进程的数据,一并发送)
  • Silly window syndrome(接收方缓存已满,但每次应用进程只读取一个字节

总的原则就是:发送方不要发送很小的报文,同时接收方也不要刚有一点空间就将窗口告知发送方

拥塞控制

  • 慢启动(slowstart)
  • 拥塞避免(congestion avoidance)
  • 快重传(fast retransmit)
  • 快恢复(fast recovery)

拥塞控制

TCP滑动窗口实现

案例

假设数据流向是A到B。

构造发送窗口

此时A收到B发过来的确认报文段,窗口是20,确认号是31,根据这两个数据构造出A的发送窗口。

发送

可以看出A由P1,P2,P3这3个指针描述了一个完整的发送窗口状态。

接受窗口B收到了32,33号,但B给出的确认报文字段中仍然是31,不能是32或者33。

3

B收到了31号的数据,B的窗口向前移动3个序号,同时发送给A确认,窗口仍然是20,确认号是33,B还收到了37,38,40字段,由于没有按序到达,所以暂存在接收窗口中。

最终可以看到,A发送了所有数据,P2和P3重合,由于没有收到确认,所以只能等待,如果发现超时,就重传数据。

这个过程有几点需要说明:

  • A的发送窗口并不是不变的,也不一定等于B的接收窗口,会根据网络情况适当调整。
  • 对于没有按序到达的数据,接收方会临时暂存。
  • TCP要求接收方必须能累积确认,可减小开销。就是说不用每次就确认,但也不能过分推迟,这样可能造成不必要的重传。

超时重传时间的选择

这是一个比较纠结的问题,因为每个报文的路由都有可能不同,有的快,有的慢。

自适应的解决方案,TCP会维护一个RTTs的值,叫做加权往返时间

新的RTTs = (1 - α) × 旧的RTTs + α × 新的RTT样本

RFC2988推荐的α值0.125

显然,重传超时时间RTO应略大于RTTs

RTO = RTTs + 4 × RTTd

RTTd是RTT的加权平均值

新的RTTd = (1 - β) × 旧的RTTd + β × |RTTs - 新的RTT样本|

RFC2988推荐的β值0.25

这里有个问题,如果TCP发生了重传,那么RTT就是不确定的,因为发送方,不知道是重传的ACK还是第一次传的ACK。这样就会严重影响RTO,所以,后来又规定,只要发生重传,就不更新RTTs。

但是又有新的问题,如果一段时间内报文时延突然变大,很多都超时了,这时RTO却无法更新,为了解决这个问题,后来又规定,报文每重传一次,RTO就增加一些,典型的做法是×2,实践证明,这样比较合理。

重传机制

  • 死等
  • 仅重传Timeout的包
  • 重传Timeout后所有的数据
  • 快重传(Fast Retransmit)
  • SACK方式

快重传

连续收到3个 ACK,则重传

Fast Retransmit

SACK

SACK 中携带已收到的报文序号段

SACK