传输层概述

目标:理解传输层的工作原理

  • 多路复用/解复用
  • 可靠数据传输原理
    • TCP对上层的应用提供可靠的服务,但是下层的IP都是不可靠的,这怎么保证呢?
  • 流量控制
    • 一个进程和另一个进程的流量控制
  • 拥塞控制
    • 大的角度,整个网络的拥塞

传输服务和协议

传输层为应用进程间提供逻辑的通信

就是应用进程把报文逻辑上发给对方,然后再从对方接收。

但是从物理上,它还要下面一层一层的来传输信息通信,比如下面的网络层的服务,就能传到对面的网络层,然后再交给上层的TCP。


传输层的发送方把应用层的报文分割成报文段,然后传递给网络层,然后接收方将报文段重组成报文,然后传递给它的应用层。

(这里忽略掉下层网络层的工作,从递归的形式来说的)

网络层与传输层

网络层:主机到主机的服务

传输层:主机进程的服务到另一个进程的服务。

网络层给传输层提供的服务是不可靠的,可能乱序、丢失啥的,但是传输层给应用层提供的服务是可靠的,因此会在传输层处会处理这种不可靠。

但是有些东西是传输层处理不了的,不能加强,比如时延、带宽……

源端到目标端叫复用,目标端到源端叫解复用 ???

相当于收发快递 ?……后面再看

传输层协议

  • 可靠、有序的传输:TCP
    • 多路复用、解复用
    • 拥塞控制
    • 流量控制
    • 建立连接
    • 字节流
  • 不可靠、无序的传输:UDP
    • 多路复用、解复用
    • 没有为IP服务加强更多其它的服务
    • 数据报
  • 都不提供的服务
    • 延时
    • 带宽

多路复用和解复用

传输层上怎么区分各个不同的进程呢?增加了端口号来区分。

下面来讲讲它是怎么多路复用和解复用

多路复用其实就是传输层接收从应用层来的各个数据,封装上首部

TCP的多路复用和解复用

一台主机上的某个进程,与另一台主机的其它进程通信,首先在应用层,它是使用套接字进行传输,套接字上有源IP、源端口、目标IP、目标端口,那应用层往下交付给传输层的时候,会把套接字上的源端口和目标端口拿出来,放到TCP的头部中,然后与要传送的信息组合成一个TCP段(当然这里就先忽略HTTP报文拆分成几个TCP段这些)。然后传输层向网络层交付的时候,再把套接字的源IP地址和目标IP地址拿出来,放到IP包的首部中,然后再往下传输。发送的部分大致就是这样。

网络层往下的部分暂时先不看了,我们认为它能逻辑地把包传输到对应主机的网络层。然后在网络层的IP包中,从它的头部中可以拿到对应的IP地址,来判断是不是自己接受的包。网络层再向传输层交付,仍然是把头部信息取出,这样就能拿到端口号了,然后根据IP和端口号信息,可以查到是哪个socket进行通信。这样就实现了解复用。

TCP套接字是由一个四元组(源IP地址、源端口号,目的IP地址,目的端口号)来标识的。

UDP的多路复用和解复用

UDP报文中只有源端口和目的端口号,一个UDP套接字是由一个含有目的IP地址和目的端口号的二元组来全面标识的。

其实大体步骤和上面的差不多,而且UDP也有一个结构体的数据存放着本机的IP地址和端口号,从应用层往下交付的时候,同样能给出要交付的对象。

无连接传输:UDP 用户数据包协议

特性

在IP的基础上,没有增加什么服务,只是多了一个多路复用/解复用,所以它和IP差不多,都是尽力而为的,有可能丢,也有可能乱序。

UDP发送端和接收端没有先建立连接,直接发的,只是知道要和谁通信,通信的信息是什么。

每个报文都独立的处理,就是发完这个,这个UDP报文就完成任务了,而不会管其它报文。

应用场景

  • 流媒体(丢失不敏感,但是速率敏感,比如聊天,应用可控制传输速率)
  • DNS
  • SNMP

如果……又想快,又想可靠?可以在应用层中校验可靠。

UDP数据报

它由8个字节的头部+报文部分。

头部:源端口+目的端口+长度+校验和(差错校验码EDC,),每个都是2个字节。


为什么要有UDP ?

  • 不建立连接
  • 简单:不用维护连接状态
  • 头部小,开销小
    • TCP要20字节!
  • 无拥塞控制和流量控制
    • 能发很快,应用层发到传输层的速度和传输到别的应用的速度是一样的

校验和

差错检测

检验和是为了校验报文有没有出错,包括头部和数据,如果发现出错了就被丢掉了。

这里还有残存错误,就是中间出错了,内容和校验和都错了!但是它们又恰好能对应起来,这样就“没错”,但实际上错了……

如何检测

把要检测的所有部分分割成一份份16bit,然后加起来就是。

注意两个细节:

  • 进位回滚
    • 加起来如果溢出了,那就把进位再加到和上
  • 反码
    • 再把计算出来的结果进行反码运算

##### 目标端怎么验证呢?

把要检测的范围和EDC分割成16bit,再进行相加(同样要进位回滚)。

如果是16位全1,就通过了校验。


我真傻!可以拆分成两个部分来看。

要检测的范围,把它拆成16bit加起来,就是反码前的EDC了。

但是EDC那部分是反码后的了,原码和反码加起来,那就是全1了。

可靠数据传输(rdt)的原理

描述

它在应用层、传输层、数据链路层都很重要,是网络的Top10问题之一。

信道的不可靠特点决定了可靠数据传输协议的复杂性。
image-20210701181035984

(这里好像是传输层)上层调用rdt_send()接口,然后把数据发送出去,这些是操作系统的一些函数,然后rdt调用下层的udt_send(),将分组数据放到不可靠信道传输到接收方;当分组通过信道到达接收方时,它会使用udt_rcv()来接收数据,然后rdt再通过deliver_data()将数据交到上层。

底层channel的不可靠决定了tcp层需要做多大的努力。

渐进的角度观察如何才能可靠

rdt1.0 可靠信道

下层的信道是完全可靠的,没有bit出错、没有丢失。

那发送方直接发,接收方直接收就行了!

  • 发送方将数据发送到下层信道
  • 接收方从下层信道接收数据

所以这个1.0啥都没干。

rdt2.0 具有比特差别的信道

下层信道可能出错,将分组中的比特翻转。

  • 校验和

如果信道接收的数据没问题,那接收方会返回一个ACK给发送方,表示这个数据没问题(发送方会等待这个结果 ?)

如果有问题,接收方会返回一个NAK,表示数据校验有问题,然后发送方就会重新发送数据,直到收到一个正确的。

ACK/NAK的错误——rdt2.1的修复

万一,ACK/NAK出错了,发送方应该反应什么呢?接着发新的数据还是发老的呢?

可以通过加序号

假如发了数据P0,然后接收到一个错误的ACK/NCK,那就不该发P1,应该把P0。接收方知道自己又收到一个P0,就知道自己的ACK/NCK发错了,虽然是重复了,但是这个是很容易检测到的。

这种。。是停止等待协议,会等确认,不会像流水线一样一直发发发。


这个加序号,好像……

只要加一个就行了,因为它是停止等待的。

要接收的是序号与期望等待的序号一致,才是接收正确的。

而且他不安排确认的确认,接收方可以根据发送方发来的分组的情况来判断自己之前的分组到底是正确还是错误的。

它的序号只有0和1,假设传输不会出错,那对于接收方,第一次收0,第二次收1,第三次收0,第四次收1……

rdt2.2 无NAK的协议

功能同rdt2.1,但是只使用ACK。

它更像一种优化,在ACK中带上编号

为停止等待协议==》流水线的转变作准备。

用前面分组的正向确认来替代当前分组的反向确认。比如接收放收到1,但是却发回ACK0,就表示当前这个1有问题。

信息处理变得更简单,减少了状态量

rdt3.0 具有比特差错和分组丢失的信道

如果发送方发了一个P1,丢失了,会造成死锁:发送方在等待ACK确认,接收方在等待P1数据。

这里需要发送方添加一个超时重传机制。设置一个比RTT多一点的时间,超过这个时间没有收到回复,就认为它丢失了,重传。

正常地收发数据:发送方发P0,接收方回复ACK0,接下来发送方发P1,如果P1回复ACK0,就表示这个P1有问题,接下来要重新发新P1;若发送方一直收不到回复,那就看超时计时器,超时前收到回复就正常,不然就是有问题,需要重传。

其实如果收到不恰当的ACK回复,可以有两种选择,一种是马上回复,一种是等超时计时器到期再回复。


超时定时期的设置也是要合理的。

  • 过早超时
    • 还能正常的通信
    • 效率低,一半的分组和确认都是重复的

效率不高,举个例子:发送方发一个P0,收到ACK0,然后发P1,但是ACK1由于某些原因来晚了,那发送方会重新发送P1,不一会,当发送方收到晚到的ACK1,那就会发新的P0(序号是0101交替的),然后接收方收到重发的P1时,又会发送一个新的ACK1,收到ACK1,那还会把P0给发一遍……

所以它发了两次P0……能正常工作,但是多发了一次。

但是,它能够对抗一些复杂的情况,但是停止等待协议还是有、“问题”:效率太低

性能

当信道容量比较大的时候,它的效率很低,原因在这个停止等待协议上。

假如,端对端的延时是15ms,RTT=30ms。

L=1KB=1000B

带宽R=1Gbps

L/R=8us,这占30ms非常小的比例, 就是说对于发送方来说,就是发送信息8us后就没事干了,剩下的30ms都是闲的。

利用率约为0.027%,非常低!有效吞吐270Kbps。

这里很明显可以看错,问题出在那个等待中。

流水线协议

允许发送方一次发送多个未经确认的分组的协议就是流水线。

  • 增加序号的范围,不再是0、1
  • 需要有缓冲区
    • 发送方缓冲:未得到确认,可能需要重传
    • 接收方缓存:速率不匹配;乱序需要排序

有两种方式Go Back N选择性重传

滑动窗口协议

铺垫一下,简单介绍一下。

  • 发送窗口=1、接收窗口=1:停止等待协议
  • 发送窗口>1、接收窗口=1:GBN(累积确认)
  • 发送窗口>1、接收窗口>1:SR(独立确认)
一些概念

发送缓冲区:发送方发送完毕后,把分组放在缓冲区中,以防备重发。它是内存中的一个位置 。

发送缓冲区的大小决定着它一次能发送多少个未经确认的分组,它有上限的,不能无限增大。

发送方可以把缓冲区的数据直接发送走,存放的是已发送还未确认的,当确认之后才从缓冲区中删除。

发送窗口:是缓冲区的子集,存放的是已发送还未确认的分组的范围。每发送一个分组,就会向前移一个位置 ,前沿的极限是发送缓冲区的上限;收到确认后,后沿会向前,这样就能为窗口腾出空间,可以准备发送新的分组。


接收窗口:有哪些分组可以被接收,只有在窗口中的才会接收,别的不收,其实和发送窗口是相对应的一个概念。

万一来了后面的分组呢?比如一个窗口,012,0和1到了,但是2没到,此时3到了,怎么办?

不接收!返回ACK=1。若再来一个4,还是不收,返回ACK=1,说明我只收到1号,需要继续发。

反正只要在接收窗口中,就可以接收,即使不是按顺序的,比如接收窗口23456,收到了3,可以接收,并且向对方发出确认ACK3,但是窗口不会移动。(接收窗口 > 1,可以乱序接收)现在收到了2,那就确认ACK2,然后移动窗口。

由上面可以看出,高序号分组乱序排列,它是缓存但不交付

正常情况下两个窗口的互动
  • 发送窗口
    • 上层应用有新的数据要发送,那就会有新的分组落入,发送方就发送,窗口前沿滑动。
  • 接收窗口
    • 收到分组,落入到接收窗口范围中,接收。
    • 是低序号,发送确认给对方
  • 发送窗口
    • 来了老的低序号分组的确认,窗口后沿向前滑动,新的窗口可以落入发送缓冲区的范围。
    • 然后再继续发送,窗口前沿滑动……

(按顺序从上往下看……)

它们两个互相带动

异常情况下GBN的窗口互动

GBN是指发送窗口>1,接收窗口=1.

  • 发送窗口
    • 新分组落入发送缓冲区范围,发送窗口前沿滑动。
  • 接收窗口
    • 【异常】收到乱序分组,没有落入接收窗口的范围,抛弃
    • 发送顺序到来的最后一个分组的确认。
  • 发送窗口
    • 不能向前滑动,只有等超时重传,然后重发
    • 把所有已发送但是未确认的分组重发
异常情况下SR的窗口互动

主要感觉一下它与GBN的异同。

对接收方:

  • 乱序到达,在接收窗口的范围中,会发送ACKn的回复
  • 单独的确认收到的分组

对发送方:

  • 若某个分组的计时器超时了,仅会发送超时的分组
  • 这就是“选择性重发”

乱序接收的前提是能收,它的接收窗口>1,与GBN的接收窗口=1不同,能够在缓冲区中保存(buffer)着,等待全部到了,然后有序的交给(deliver)上层应用层。

GBN和SR的异同

GBN:

  • 简单,所需资源少
  • 但是一旦出错,回退N步的代价太大了

SR:

  • 出错时,重传一个代价小
  • 复杂,所需资源多(接收方多个缓存单元)

适用范围:

  • 出错率低:适用GBN,出错其实是非常罕见的,没必要用复杂的SR。
  • 链路容量大(延迟大、带宽大):比较适合SR,一旦出错代价太大

TCP

概述

TCP概述:

它是一个点对点的服务,即一个发送方,一个接收方。

它向上层提供可靠的字节流服务。

提供一个管道化(或者流水线)的协议,发送方在未经确认的情况下,可以向接收方发送多个段,按照MSS(Max Segement Size)的大小把报文切分,因为MTU是1500B,TCP占20、IP占20,那剩下的只有1460B,超过这个的就要切分。

同时,它也有发送和接收缓冲区,一是上面说的rdt,二则是拥塞控制和流量控制这些。

在传输中,它是全双工数据,双向流通的。

为了保证这个可靠传输,它是面向连接的

TCP报文段结构

image-20210702121913137

  • 源端口号,长度16bit
  • 目的端口号,长度16bit
  • 序号seq,长度32bit
    • 上层传下来的报文需要拆分成一个个MSS
    • 序号就是MSS的偏移量,也就是该报文段在字节流中的编号
    • 初始为x,第二个就是x+MSS,第三个就是x+2*MSS……
  • 确认号ACK,长度32bit
    • 与上面的序号相对应。
    • 收到ACK=555,就表示554及以前的分组数据都收到了,有累积确认的
    • 期望发送方发送555和它之后的数据
  • 首部长度+保留+UAPRSF……共16bit,具体看上图。
  • 接收窗口,16bit
    • 用于流量控制,表示接收方可以接收多少的分组
  • 校验和
    • 同之前HTTP
  • 紧急数据指针
    • 古老的东西

TCP往返延迟

一个合理的超时定时器是很必要的。

比RTT长 ?但RTT是会变化的

太短? 太早超时,引起不必要的重传

太长? 对报文段丢失的反应太慢,消极


怎样估计RTT?

这里采用一个自适应的方法。

在一个比较短的时候,它的RTT是比较集中的。

  • SampleRTT:测量从报文段发出到确认的时间(忽略重传)
  • 它会变化,而且变化很大,所以需要求平均。
  • 平均值+4*方差

指数加权移动平均

EstimatedRTT=(1-a)EstimatedRTT+a*SampleRTT

可靠数据传输

TCP在IP不可靠服务的基础上建立了rdt。

  • 管道化的报文段
    • GBN or SR,混合体
    • 只设置一个超时计时器,看最老未确认的分组。超时了就重发这个分组。
    • 对于乱序的分组,TCP协议未作约定,可以缓存或者丢掉。
    • 收到对方三个冗余确认,并且这个分组还没有超时,这时也会触发重发。这叫快速重传。

TCP发送方事件

  • 从应用层接收数据
    • 用nextseq创建报文段
    • 序号nextseq为报文段首字节的字节流编号
    • 如果还没有运行,启动计时器(与最早未确认报文段关联)
  • 超时
    • 重传最老的报文段
    • 重新启动定时器
  • 收到确认
    • 如果是对尚未确认的报文段进行确认
      • 更新已被确认的报文序号
      • 如果还有未被确认的报文段,重启定时器

重传改进

关于重传,有这么些建议?

  • 辅助计时器,比如500ms,不是马上发送确认,而是等待500ms之后再一起发。
  • 上面的改进:如果等待过程中又收到重复的信息,那就马上发送数据。
  • 收到乱序的数据,就马上把当前期待的最早分组的确认发给对方(就是快点发前面的给我,后面的数据都已经到了!)
  • 上面的改进:如果最前面部分补齐了,马上发送中间gap的确认

快速重传

收到对方三个冗余确认,并且这个分组还没有超时,这时也会触发重发。

可以理解为,中间的慢了,后面的三块都到了,或者说中间的丢掉了……

流量控制

目的:防止发送方发得太快,超过了接收方的处理能力。

通过捎带技术,让接收方利用TCP报文的接收窗口的字段来反馈给发送方,以免发送方发太快而接收方没有空间存放这么多数据。

连接管理

好像就是三次握手、四次挥手的东西。

建立连接,删除连接……

建立连接(三次握手)

要建立连接,要知道要和对方通信,双方需要准备一些资源,还要作一些置位啥的前期操作。

下面都是A和B进行通信,一些前置性的描述就省略了。

两次握手 ?不行!

两次到底可以不可以呢?

C:我们开始通信吧?

S:ok!

仅仅是连接请求、连接确认,不行!因为无法应对这些请求和丢失或延迟。


C发送请求,然后S回应,但是这个回应晚了,C的超时计时器时间到了,会又向S发送一个请求连接。

此时,S的回应到了C,然后与C建立了连接,然后C刚刚发的请求又到了S,S作为服务器仍然同意建立连接,给C发一个回应。

但是!C已经与S建立了连接,就不会管这个回应,于是S就会维护这个半连接,这种虚假的半连接会耗费服务器的资源。

而且,如果在两次握手建立连接后,传输数据时,会有老数据被当成新数据处理的可能。还是像上面一样,S对C的建立连接请求的回应慢了,导致C重发一个请求。

但是在S收到这个请求之前(这个请求又慢了!)C给S发了数据,超时,然后又重发,S接收了,然后断开连接。

此时,S收到C之前重发的请求,然后建立连接,然后又收到那个重发的超时的数据……这个旧的重发的数据被当成新的数据,被客户端接收了。

image-20210702170152050


三次握手才是正确

  • C建立连接,选择初始序号Seq=x,SYN=1连接请求。

  • S确认,并且也发送一个SYN=1的连接请求,同时还有Seq=y,ACK=1;另外还对C表示确认,ACKnum=x+1

  • C收到后,确认他的连接,ACK=1,ACKnum=y+1.

其实相当于“四次握手”,省略中间的。C给S一个x,然后S给C确认x+1;反过来对于S,也给C一个y,C收到也会给S一个y+1。

有个小细节 ?第三次交付通常和第一次数据传递弄在一起。

它解决了两次握手的问题:半连接接收老数据

  • 半连接问题

    迟到的连接请求到了服务器S,服务器表示同意和你连接,但是回应到了客户端,由于是三次握手,客户端知道这是过期的,会拒绝!

  • 接收老数据

    其实三次握手把半连接问题解决了,这个问题也顺带解决得差不多了。

    传递重发的老数据,服务器可能认为:服务器没有和客户端建立连接,为什么客户端要发数据给我?

    也有可能一次正常的建立连接、发送数据、断开连接后,又重新建立连接,然后上一次正常连接的延迟很严重的老数据发过来了,服务器会接收吗?不会,因为还有序号!建立时序号是随机的,对不上号的数据肯定会被丢弃。

    当然,也有随机的可能,网络不能解决所有问题。他列举了一个时钟周期来解决……

释放连接

有建立就有释放。

两个方向单独拆除连接!把它分为两个“半连接”,两边都拆掉。

但是它有些问题,可能会有问题。

讲了一个“两军问题”23333333333用来说明这种单边的连接释放是不可靠的。

客户端、服务器分别关闭自己这一侧的连接

  • 发送FIN=1的TCP段

  • 一旦收到FIN,用ACK回应。

发完之后,有一个2mst的计时器,再无连接就算完成释放了。

image-20210702172721580

拥塞控制原理

概述

非正式的定义:太多的数据需要网络传输,超过了网络的处理能力。

它和流量控制不一样,网络是一个大的概念,大家一起用的网络。

大家都传数据,会导致数据包丢失或者时延过大。

原因

场景1:路由器缓冲无限

主机向服务器发送数据,假设只通过一个路由器,有无限大的缓冲,假设带宽为R。

可以知道,它的吞吐量最大就是$R/2$,入=出,一人一半嘛。

但是排队延迟会抖增,变得非常慢!

这听着它的使用率很高,传多少就能马上收多少,但是分组在路由器上需要排队很久,就是延迟特别大。

场景2:路由器缓冲有限

a:知道缓冲什么时候可用

发送方有完美的信息,知道路由器缓冲是可用的。

只有在缓冲可用的时候才发送,不会丢失

原数据和重发的数据速率相同。

b:掌握丢失信息

分组可以丢失(在路由器缓冲区满的时候)

如果丢失了,会重传。

所以它的发送速率随着流量的大小而增大,和上面一样,也是最多却分不到一半。

由于有重传的分组,就发送的速率比接收的数据多。它是渐进逼近$R/2$。

因为它需要有效的输出(让服务器收到信息?),网络做了更多的工作,比如重传。而这种重传有可能是不必要的,比如有个分组传得慢,超时重传了,然而它并不是丢失了,而是在缓冲区中等待,于是就有份重复的分组了。然而正是因为它延迟高了,这种重传会加剧网络的拥塞

场景3:多路径传

多个发送端、多个接收端,他们的路径还不一样。

这个场景是指大家都在网络上跑,多个链路经过同一个路由器,互相争抢流量,但是最终谁也不能发完……

拥塞控制方法

网络其实是想尽可能增大发送速率,但是又不想让它发生拥塞。

端到端拥塞控制

网络不提供任何拥塞信息,靠端系统自己的判断来判断是否拥塞,从而改变发送速率。

比如快速重传,收到三个丢失分组的信息,就可以判断网络可能拥塞,就可能降低网络传输的速率。

网络辅助的拥塞控制

就是网络提供一些拥塞信息给端系统,端系统根据反馈的信息判断拥塞程序,来决定增加或减少网络流量 。

样例

ATM ABR(available bit rate) 拥塞控制

ATM是一个异步传输网络,它的数据交换单位是信元,可以认为它是一个小分组(53B=5B+48B)

每个交换节点中,消耗时间比分组小,比单比特的大,而且它的时间是固定的。

它有很多模式

ABR

提供一种弹性服务。

端到端的。

在网络比较轻载时,尽可能使用带宽,有多少用多少。

但是万一发生拥塞,就会限制在一个最小保障中。

RM(资源管理)信元

信元除了数据信元外,还有一种叫RM的信元,它有一些特殊的字段,用于标记网络拥塞的状态。

在网络发生轻微拥塞的时候,会相应给RM置位,比如把NI置位,表示不要再增加速率了。

若网络发生明显的拥塞时,给RM的CI置位,不但不能增加速率,还要降低。

另外,还有一个叫做ER的字段,表示的是可以为你提供多少带宽,这样端主机就知道链路上各主机能提供的最大速率。

TCP拥塞

机制

它采用的是端到端的拥塞控制,靠端到端的信息自己判断,而不依靠网络的信息。

采用这种架构,重点就在于端系统的设计,而网络核心提供最小规模的提供。

它要面对的问题和上面

拥塞感知

某个段超时了(丢失事件)

超时时间到了,某个段的确认还没到。

有可能的原因是:

分组到路由器的时候,缓冲区满了,分组被抛弃掉。

但是这个就能说明拥塞的吗?万一是半路遇到干扰,不能经过校验,那也一样会造成“分组被抛弃”的情况。

其实这种误操作占比还是很小的,但是这个方向还是可以的,只要超时了就认为拥塞,然后不增加或降低发送速率。

三个冗余ACK

回忆“快速重传部分”。

收到连续三个冗余确认(一共四个),可能是中间有一个分组丢了,但是后面的分组到了接收方,所以就有冗余的三个确认。

这时超时计时器还没触发(它的设定比较保守)那这样会触发快速重传,把对方期待的分组接收到,并且知道网络将要发生拥塞

速率控制方法

维护一个拥塞窗口的值:CongWin

它把速率控制在窗口/RTT的范围中。

虽然不大精确,但是发送方能限制已发送但是还没确认的数据量的上限,这种反馈非常重要。


CongWin是动态的。(下面按顺序来看!)

  • 超时
    • CongWin设置为1个MSS
    • 进入ss(慢启动)阶段(翻倍、翻倍、翻倍……)
  • 收到三个冗余ACK后
    • CongWin降为一半
    • 进入CA(拥塞避免)阶段(一个一个MSS地加)

拥塞控制和流量控制的联合动作

流量控制+拥塞控制,两个愿望,一次满足【x】

发送端控制发送但是没确认的,但是同时也不能超过接收窗口,满足流量控制的要求。

SendWin = min(CongWin, RecvWin)

拥塞策略概述

拥塞控制策略:

  • 慢启动
  • AIMD:线性增、乘性减
  • 超时事件后的保守策略

TCP慢启动

连接刚建立,CongWin=1

比如,MSS=1460B,RTT=200ms,算下来的话初始速率只有58.4kbps,非常小。

所以此时应该尽可能地加速

因此,以指数形式加速!尽管初始速率很慢。

所以SS阶段的时间持续很短。(网络肯定会堵,因此……)

什么时候将指数增长变为线性?

设置一个门限值Threshold

超时之后,记录CongWin/2,把它记为Threshold

重新,从1个MSS开始,指数增加,直到Threshold门限值。

此时由指数增长转为线性增长,一个一个MSS地加!

AIMD拥塞避免

指数增长超时后,设置门限值,并且回到1个MSS。

从1个MSS指数增长到门限值,这个过程很快的。(甚至可以忽略)

然后进入拥塞避免状态,一个一个MSS地加,这个就是拥塞避免阶段。

万一此时超时了,那就继续慢启动步骤,门限值设为拥塞窗口的一半,然后再从1个MSS开始……

这个图画出来就像锯尺型。

小结

  • CongWin > Threshold,慢启动阶段,窗口指数增长。
  • CongWin < Threshold,拥塞避免阶段,窗口线性增长。
  • 收到三个重复ACK,快速重传,Threshold=CongWin /2,CongWin=Threshold+3。这里是轻微拥塞的时候。
  • 超时,Threshold=CongWin /2,CongWin=1MSS,慢启动……

其它细节

吞吐量

假设拥塞窗口值是W。

那任一阶段都在2/W到W之间波动,它平均就是3/4W,又知RTT,则能求出它的平均吞吐量。

公平性

假设两个主机对A、B共享了一个瓶颈式的带宽。

长期来看,A对、B对都是占据一半的。

是公平的。

为什么 ?

变回一半。会收敛到中间……

这个原理真厉害……