Skip to content

3. 传输层

C. Yin edited this page Feb 20, 2024 · 1 revision

目标:

  • 理解传输层的工作原理
    • 多路复用/解复用
    • 可靠数据传输(reliable data transfer, RDT)
    • 流量控制
    • 拥塞控制
  • 学习Internet的传输层协议
    • UDP:无连接传输
    • TCP:面向连接的可靠传输
    • TCP的拥塞控制

3.1 概述和传输层服务

传输服务和协议

  • 为运行在不同主机上的应用进程提供逻辑通信(看上去是通过socket api将数据传给另一个进程,实际上报文需要通过层间接口交给传输层,通过两个传输层之间的相互配合交给另一方对等的应用进程)
  • 传输协议运行在端系统
    • 发送方:将应用层的报文分成报文段,然后传递给网络层
    • 接收方:将报文段重组成报文,然后传递给应用层
  • 有多个传输层协议可供应用选择
    • Internet:TCP和UDP

传输层 vs. 网络层

  • 网络层服务(IP协议):主机之间的逻辑通信
  • 传输层服务:将主机-主机的通信细分为进程间的逻辑通信
    • 依赖于网络层的服务(IP协议),依靠传输层无法加强
      • 延时(传输、传播、排队等)、带宽(吞吐量,瓶颈链路)
    • 并对网络层的服务进行增强(IP向上层提供的服务不可靠,TCP将不可靠变为可靠:RDT。通过SSL将TCP由不安全变为安全)
      • 数据丢失、顺序混乱、加密

复用/解复用:类比:东、西2个家庭的通信

Ann家的12个小孩给另Bill家的12个小孩发信

  • 主机 = 家庭
  • 进程 = 小孩
  • 应用层报文 = 信封中的信件
  • 传输协议 = Ann 和 Bill
    • 为家庭小孩提供复用、解复用服务(Ann将信件复用(打包)发给邮政服务,Bill从邮政服务收到后进行解复用(拆包分发))
  • 网络层协议 = 邮政服务
    • 家庭-家庭的邮包传输服务

有些服务是可以加强的:不可靠 -> 可靠;安全
但有些服务是不可以被加强的:带宽,延迟

Internet传输层协议

  • 可靠的、保序的传输:TCP
    • 多路复用、解复用
    • 拥塞控制
    • 流量控制
    • 建立连接
  • 不可靠、不保序的传输:UDP
    • 多路复用、解复用
    • 没有为尽力而为的IP服务添加更多的其它额外服务
  • 都不提供的服务(依赖于网络层):
    • 延时保证
    • 带宽保证

3.2 多路复用与解复用

复用:多个进程应用进程借助一个TCP或UDP实体来发送

在发送方主机多路复用:
从多个套接字接收来自多个进程的报文,根据套接字对应的IP地址和端口号等信息对报文段用头部加以封装(该头部信息用于以后的解复用)

  • TCP复用:source port and destination port (TCP header) + message,通过层间接口来到网络层,加上IP头部:IP header(source IP and destination IP) + TCP header + message
  • UDP复用:应用进程往下交 1.message 2.socket(source IP and source port) 3.&cad(destination IP and destination port) 给UDP传输层,UDP得到源端口和目标端口并封装信息交给IP网络层,IP知道源IP、目标IP,即可将报文打出

在接收方主机多路解复用:
根据报文段的头部信息中的IP地址和端口号将接收到的报文段发给正确的套接字(和对应的应用进程)

  • TCP解复用:收到IP数据报后,拿出IP body部分即TCP段,从TCP头部提取源端口、目标端口,从IP头部提取出源IP、目标IP,从而查询到相应的socket,进而发给相应的进程
  • UDP解复用:IP传上来的报文中有源端口和目标端口,通过查询相应的socket发给相应的进程

多路解复用工作原理(UDP和TCP不同)

  • 解复用作用:TCP或者UDP实体采用哪些信息,将报文段的数据部分交给正确的socket,从而交给正确的进程
  • 主机收到IP数据报
    • 每个数据报有源IP地址和目标地址
    • 每个数据报承载一个传输层报文段
    • 每个报文段有一个源端口号和目标端口号(特定应用有著名的端口号)
  • 主机联合使用IP地址端口号将报文段发送给合适的套接字
TCP/UDP报文段格式(32 bit)
source port and destination port
other header
application layer message

无连接(UDP)多路解复用

  • 创建套接字:
    • 服务器端:serverSocket 和 Sad 指定的端口号捆绑
      serverSocket = socket(PF_INET, SOCK_DGRAM, 0);
      bind(serverSocket, &sad, sizeof(sad));
      
    • 客户端:没有 Bind,ClientSocket 和 OS 为之分配的某个端口号捆绑(客户端使用什么端口号无所谓,客户端主动找服务器)
      ClientSocket=socket(PF_INET, SOCK_DGRAM, 0);
      
    • 在接收端,UDP套接字用二元组标识:(destination IP address, destination port)
    • 当主机收到UDP报文段:
      • 检查报文段的目标端口号
      • 用该端口号将报文段定位给套接字
    • 如果两个不同源IP地址/源端口号的数据报,但是有相同的目标IP地址和端口号,则被定位到相同的目标UDP套接字。

      例子:

面向连接(TCP)的多路复用

  • TCP套接字:四元组本地标识:(源IP地址, 源端口号, 目标IP地址, 目标端口号)
  • 解复用:接收主机用这四个值来将数据报定位到合适的套接字
  • 服务器能够在一个TCP端口上同时支持多个TCP套接字:
    • 每个套接字由其四元组标识(有不同的源IP和源PORT)

    例子:

  • Web服务器对每个连接客户端有不同的套接字
    • 非持久对每个请求有不同的套接字

面向连接的多路复用:多线程Web Server

  • 一个进程下面可能有多个线程:由多个线程分别为客户提供服务
  • 在这个场景下,还是根据4元组决定将报文段内容同一个进程下的不同线程
  • 解复用到不同线程(与解复用到不同进程相似)

3.3 无连接传输:UDP

UDP(User Datagram Protocol [RFC 768]):用户数据报协议

  • “no frills,” “bare bones”Internet传输协议
  • “尽力而为”的服务,报文段可能丢失也可能送到应用进程的报文段乱序
  • 无连接:
    • UDP发送端和接收端之间没有握手
    • 每个UDP报文段都被独立地处理
  • UDP被用于:
    • 流媒体(丢失不敏感,速率敏感、应用可控制传输速率)
    • DNS
    • SNMP(简单网络管理协议)
  • 在UDP上可行可靠传输:
    • 在应用层增加可靠性
    • 应用特定的差错恢复

UDP报文段格式

为什么要有UDP?

  • 不建立连接(若要先建立连接则会增加延时)
  • 简单:在发送端和接收端没有连接状态
  • 报文段的头部很小(开销小:头部只有8个字节,而TCP有20个字节)
  • 无拥塞控制和流量控制:UDP可以尽可能快的发送报文段
    • 应用层->传输层的速率 = 主机->网络的速率 (上面来多快,往下发就多快)

UDP校验和(校验和:EDC,差错检测码)

  • 目标:检测在被传输报文段中的差错(如比特反转),若出错,这个UDP数据报就会被扔掉(表现为丢失)
  • 发送方:
    • 将报文段的内容视为16比特的整数(每16bit切一段,得到一系列二进制整数)
    • 校验和:报文段的加法和(1的补运算)
    • 发送方将校验和放在UDP的校验和字段
  • 接收方:
    • 计算接收到的报文段的校验和
    • 检查计算出的校验和与校验和字段的内容是否相等:
      • 不相等 --> 检测到差错
      • 相等 --> 没有检测到差错,但也许还是有差错
        • 残存错误(校验范围 + 校验和 = 1111111111111111,但是两个加数都出错了)

Internet校验和的例子:两个16bit的整数相加

注意:当数字相加时,在最高位的进位要回卷,再加到结果上(即最高位的进位数字与末位相加,重新计算得到和)

  • 目标端:校验范围 + 校验和 = 1111111111111111 通过校验
    • 否则没有通过校验
  • 注:求和时,必须将进位回卷到结果上

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

rdt在应用层、传输层和数据链路层都很重要,是网络Top 10问题之一。

信道的不可靠特点(只是“尽力而为”)决定了可靠数据传输协议(rdt)的复杂性。

可靠数据传输:问题描述

udt:不可靠数据传递

我们将在本层进行如下工作:

  • 渐增式地开发可靠数据传输协议(rdt)的发送方和接收方(渐增式:从下层可靠、不丢失开始,一步步去掉假设,使下层变得越来越不可靠,从而完善rdt协议)
  • 只考虑单向数据传输
    • 但控制信息是双向流动的!(有一些反馈机制)
  • 双向的数据传输问题实际上是2个单向数据传输问题的综合(两个过程具有对称性)
  • 使用有限状态机(FSM)来描述发送方和接收方(有限状态机实际上就是描述协议如何工作的一个形式化的描述方案,比语言更加简洁易懂、便于检查)

状态:在该状态时,下一个状态只由下一个事件唯一确定。
节点之间有个状态变迁的边(edge)连在一起,代表状态1变成状态2在变迁的这条有限边上有标注。
标注有分子和分母: $\frac{引起状态变化的事件}{状态变迁时采取的动作}$

下面进行渐进式开发: Rdt1.0 --> Rdt2.0 --> Rdt2.1 --> Rdt2.2 --> Rdt 3.0

Rdt1.0:在可靠信道上的可靠数据传输

  • 下层的信道是完全可靠的
    • 没有比特出错
    • 没有分组丢失
  • 发送方和接收方的FSM
    • 发送方将数据发送到下层信道(只进行接收、封装、打走的动作,不进行其他动作)
    • 接收方从下层信道接收数据(解封装、交付)

Rdt2.0:去掉一个假设,变为具有比特差错(如0和1的反转)的信道

  • 下层信道可能会出错:将分组中的比特翻转
    • 用校验和来检测比特差错
  • 问题:怎样从差错中恢复:
    • 确认(ACK):接收方显式地告诉发送方分组已被正确接收(send ACK)
    • 否定确认(NAK):接收方显式地告诉发送方分组发生了差错(send NAK)
      • 发送方收到NAK后,发送方重传分组(之前发送完之后需要保存一个副本)
  • rdt2.0中的新机制:采用差错控制编码进行差错检测
    • 发送方差错控制编码、缓存
    • 接收方使用编码检错
    • 接收方的反馈:控制报文(ACK,NAK):接收方->发送方
    • 发送方收到反馈相应的动作(发送新的或者重发老的)

Rdt2.0:FSM描述

Rdt2.0的致命缺陷!-> Rdt2.1

  • 如果ACK/NAK出错?
    • 发送方不知道接收方发生了什么事情!(既不是ACK也不是NAK)
    • 发送方如何做?
      • 重传?可能重复
      • 不重传?可能死锁(或出错)
    • 需要引入新的机制
      • 序号
  • 处理重复:
    • 发送方在每个分组中加入序号
    • 如果ACK/NAK出错,发送方重传当前分组
    • 接收方丢弃(不发给上层)重复分组

停止等待协议(stop and wait):发送方发送一个分组,然后等待接收方的应答

讨论

  • 发送方:
    • 在分组中加入序列号
    • 只需要一位即两个序列号(0,1)就足够了
      • 一次只发送一个未经确认的分组(注:若接收方等待的是1号分组,而传来0号未出错的分组,则接收方传回ack,与发送方调成同步)
    • 必须检测ACK/NAK是否出错(需要EDC)
    • 状态数变成了两倍
      • 必须记住当前分组的序列号为0还是1
  • 接收方:
    • 必须检测接收到的分组是否是重复的
      • 状态会指示希望接收到的分组的序号为0还是1
    • 注意:接收方并不知道发送方是否正确收到了其最后发送的ACK/NAK
      • 发送方不对收到的ack/nak给确认,没有所谓的确认的确认;

      • 接收方发送ack,如果后面接收方收到的是:

        • 老分组p0?则ack错误
        • 下一个分组?P1,ack正确

Rdt2.2:无NAK、只有ACK的协议(NAK free)

  • 功能同rdt2.1,但只使用ACK(ack 要编号)
  • 接收方对最后正确接收的分组发ACK,以替代NAK(对当前分组的反向确认可由对前一项分组的正向确认代表,如用ack0代表nak1、用ack1代表nak0等等)
    • 接收方必须显式地包含被正确接收分组的序号
  • 当收到重复的ACK(如:再次收到ack0)时,发送方与收到NAK采取相同的动作:重传当前分组
  • 为后面的一次发送多个数据单位做一个准备
    • 一次能够发送多个
    • 每一个的应答都有:ACK,NACK;麻烦
    • 使用对前一个数据单位的ACK,代替本数据单位的nak
    • 确认信息减少一半,协议处理简单

Rdt2.2的运行

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

  • 新的假设:下层信道可能会丢失分组(数据或ACK)
    • 会死锁(发送方等待确认,接收方等待分组)
    • 机制还不够处理这种状况:
      • 检验和
      • 序列号
      • ACK
      • 重传
  • 方法:发送方等待ACK一段合理的时间(链路层的timeout时间是确定的,传输层timeout时间是适应式的(需要动态地计算))
    • 发送端超时重传:如果到时没有收到ACK->重传
    • 问题:如果分组(或ACK)只是被延迟了:
      • 重传将会导致数据重复,但利用序列号已经可以处理这个问题
      • 接收方必须指明被正确接收的序列号
    • 需要一个倒计数定时器

Rdt3.0的运行

  • 过早超时(延迟的ACK)也能够正常工作;但是效率较低,一半的分组和确认是重复的;
  • 设置一个合理的超时时间也是比较重要的

Rdt3.0的性能

  • rdt3.0停等协议可以工作,但链路容量比较大的情况下(分组全部放完时,分组的第一个比特离接收方还很远),性能很差
    • 链路容量比较大,一次发一个PDU的不能够充分利用链路的传输能力(信道明明可容纳很多很多包,每次却只有一个包处于信道中,信道利用率极低)

例:
$1Gbps$ 的链路, $15ms$ 端-端传播延时( $RTT = 30ms$ ),分组大小为 $1kB = 1000Bytes = 8000bits$
$$T_{transmit} = \frac{L(分组长度, 比特)}{R(传输速率, bps)} = \frac{8kb/pkt}{10^9 b/sec} = 8\mu{s}$$
$$U_{sender} = \frac{L/R}{RTT+L/R} = \frac{{0.008}}{30.008} = 0.00027$$

  • $U_{sender}$ :利用率 – 忙于发送的时间比例
  • $30ms$ 发送 $1KB$ 的分组 --> $270kbps=33.75kB/s$ 的吞吐量(在 $1Gbps$ 链路上)
  • 瓶颈在于:网络协议限制了物理资源的利用!

其中Rdt3.0:停-等操作

如何提高链路利用率?流水线(pipeline)

  • 增加 $n$ (如这里从 $n=1$ 变为 $n=3$ ),能提高链路利用率
  • 但当达到某个 $n$ ,其 $u=100%$ 时,无法再通过增加 $n$ ,提高利用率
  • 瓶颈转移了 --> 链路带宽(此时可将 $1Gbps$ 链路升级为 $10Gbps$ 链路)

流水线协议(流水线:允许发送方在未得到对方确认的情况下一次发送多个分组)

  • 必须增加序号的范围:用多个bit表示分组的序号(若分组的序号用 $N$ 个比特表示,则整个分组的空间占用是 $2^N$
  • 在发送方/接收方要有缓冲区
    • 发送方缓冲:未得到确认,可能需要重传;
    • 接收方缓存:上层用户取用数据的速率 $\neq$ 接收到的数据速率,需要缓冲来对抗数据的不一致性;接收到的数据可能乱序,排序交付(可靠)
  • 两种通用的流水线协议:回退N步(GBN)选择重传(SR)

为讲解GBN和SR协议的差别,先引入slide window协议

通用:滑动窗口(slide window)协议

sending window receiving window
= 1 = 1 stop-wait
> 1 = 1 GBN
> 1 > 1 SR

其中 sw(sending window) > 1 时也称为流水线协议

几个概念:

  • 发送缓冲区

    • 形式:内存中的一个区域,落入缓冲区的分组可以进行检错重发、超时重发
    • 功能:用于存放已发送,但是没有得到确认的分组
    • 必要性:需要重发时可用
  • 发送缓冲区的大小:一次最多可以发送多少个未经确认的分组

    • 停止等待协议=1
    • 流水线协议>1,合理的值,不能很大,链路利用率不能超100%
  • 发送缓冲区中的分组

    • 未发送的:落入发送缓冲区的分组,可以连续发送出去;
    • 已经发送出去的、等待对方确认的分组:发送缓冲区的分组只有得到确认才能删除
  • 发送窗口:发送缓冲区内容的一个范围(发送缓冲区的子集)

    • 存放那些已发送但是未经确认分组的序号构成的空间
    • 发送窗口的最大值 <= 发送缓冲区的值
    • 一开始:没有发送任何一个分组
      • 后沿 = 前沿
      • 之间为发送窗口的尺寸 = 0
    • 发送窗口的移动——前沿移动
      • 每发送一个分组,前沿前移一个单位
      • 发送窗口前沿移动的极限:(前沿和后沿的距离)不能够超过发送缓冲区
    • 发送窗口的移动——后沿移动
      • 条件:收到老分组的确认
      • 结果:发送缓冲区罩住新的分组,来了分组可以发送
      • 移动的极限:不能够超过前沿
    • 发送窗口滑动过程——相对表示方法(只是为了方便理解)
      • 采用相对移动方式表示,分组不动,窗口向前滑动(实际上真正的滑动过程为窗口不动,分组向前滑动)
      • 可缓冲范围移动,代表一段可以发送的权力
  • 接收窗口(receiving window)=接收缓冲区

    • 接收窗口用于控制哪些分组可以接收;
      • 只有收到的分组序号落入接收窗口内才允许接收
      • 若序号在接收窗口之外,则丢弃;
    • 接收窗口尺寸Wr=1,则只能顺序接收;
    • 接收窗口尺寸Wr>1,则可以乱序接收
      • 但提交给上层的分组,要按序
    • 例如:Wr=1,在0的位置;只有0号分组可以接收;向前滑动一个,罩在1的位置,此时如果来了第2号分组,则第2号分组为乱序分组,则丢弃,并给出确认:对顺序到来的最高序号的分组给确认(如此时给出ack0 注:这里的分组序号不再只有0、1两个,即不进行模2运算,只有0、1的是 停止-等待(sw)协议);
      再例如接收窗口尺寸Wr=4>1时(此时到来的分组是乱序但是落在接收缓冲区的范围之内,则也进行接收并发出确认,直到该分组之前的分组都接收到了,接收窗口才进行滑动,如下图中收到1,2分组先不滑动,收到0分组后,2分组前的分组全部收到,此时进行滑动到3号分组开始;若第一次接收到的是0号分组,则接收缓冲区立即向后滑动到1开始):
    • 接收窗口的滑动和发送确认
      • 滑动:
        • 低序号的分组到来,接收窗口移动;
        • 高序号分组乱序到,缓存但不交付(因为要实现rdt,不允许失序),不滑动
      • 发送确认:
        • 接收窗口尺寸=1;发送连续收到的最大的分组确认(累计确认:这之前的分组都正确收到了)
        • 接收窗口尺寸>1;收到分组,发送那个分组的确认(单独确认,非累计确认:只代表正确收到了这个分组)

发送窗口-接收窗口的互动

  • 正常情况下的2个窗口互动
    • 发送窗口
      • 有新的分组落入发送缓冲区范围,发送->前沿滑动
      • 来了老的低序号分组的确认->后沿向前滑动->新的分组可以落入发送缓冲区的范围
    • 接收窗口
      • 收到分组,落入到接收窗口范围内,接收
      • 是低序号,发送确认给对方
    • 发送端上面来了分组->发送窗口滑动->接收窗口滑动->发确认
  • 异常情况下GBN(wr=1)的2窗口互动
    • 发送窗口
      • 新分组落入发送缓冲区范围,发送->前沿滑动
      • 超时重发机制让发送端将发送窗口中的所有分组发送出去
      • 来了老分组的重复确认->后沿不向前滑动->新的分组无法落入发送缓冲区的范围(此时如果发送缓冲区有新的分组可以发送)
    • 接收窗口
      • 收到乱序分组,没有落入到接收窗口范围内,抛弃
      • (重复)发送老分组的确认,累计确认
  • 异常情况下SR(wr>1)的2窗口互动
    • 发送窗口
      • 新分组落入发送缓冲区范围,发送->前沿滑动
      • 超时重发机制让发送端将超时的分组重新发送出去(不像GBN需要将发送窗口中的所有分组全部重发)
      • 来了乱序分组的确认->后沿不向前滑动->新的分组无法落入发送缓冲区的范围(此时如果发送缓冲区有新的分组可以发送)
    • 接收窗口
      • 收到乱序分组,落入到接收窗口范围内,接收
      • 发送该分组的确认,单独确认

GBN协议和SR协议的异同

  • 相同之处
    • 发送窗口>1
    • 一次能够可发送多个未经确认的分组
  • 不同之处
    • GBN:接收窗口尺寸=1
      • 接收端:只能顺序接收(对顺序接收的最高序号的分组进行确认-累计确认)
        • 对乱序的分组:
          • 丢弃(不缓存)
          • 在接收方不被缓存!
      • 发送端:从表现来看,一旦一个分组没有发成功,如:0,1,2,3,4,假如1未成功,234都发送出去了,要返回1再发送;GB1
        • 只发送ACK:对顺序接收的最高序号的分组
          • 可能会产生重复的ACK
          • 只需记住expectedseqnum;接收窗口=1
            • 只一个变量就可表示接收窗口
    • SR:接收窗口尺寸>1
      • 接收端:可以乱序接收
      • 发送端:发送0,1,2,3,4,一旦1未成功,2,3,4,已发送,无需重发,选择性发送1

流水线协议:总结

  • Go-back-N (GBN) :
    • 发送端最多在流水线中有N个未确认的分组
    • 接收端只是发送累计型确认cumulative ack
      • 接收端如果发现gap,不确认新到来的分组
    • 发送端拥有对最老的未确认分组的定时器
      • 只需设置一个定时器
      • 当定时器到时时,重传所有未确认分组
  • Selective Repeat (SR) :
    • 发送端最多在流水线中有N个未确认的分组
    • 接收方对每个到来的分组单独确认individual ack(非累计确认/单独确认)
    • 发送方为每个未确认的分组保持一个定时器
      • 当超时定时器到时,只是重发到时的未确认分组

GBN的运行

选择重传SR的运行

选择重传SR

  • 接收方对每个正确接收的分组,分别发送ACKn(非累积确认)
    • 接收窗口>1
      • 可以缓存乱序的分组
    • 最终将分组按顺序交付给上层
  • 发送方只对那些没有收到ACK的分组进行重发-选择性重发(而非整个发送窗口中的分组)
    • 发送方为每个未确认的分组设定一个定时器
  • 发送窗口的最大值(发送缓冲区)限制发送未确认分组的个数
  • 发送方
    • 从上层接收数据:
      • 如果下一个可用于该分组的序号可在发送窗口中,则发送
    • timeout(n):
      • 重新发送分组n,重新设定定时器
    • ACK(n) in [sendbase,sendbase+N]:
      • 将分组n标记为已接收
      • 如n为最小未确认的分组序号,将base移到下一个未确认序号
  • 接收方
    • 分组n [rcvbase, rcvbase+N-1]
      • 发送ACK(n)
      • 乱序:缓存
      • 有序:该分组及以前缓存的序号连续的分组交付给上层,然后将窗口移到下一个仍未被接收的分组
    • 分组n [rcvbase-N, rcvbase-1]
      • ACK(n)
    • 其它:
      • 忽略该分组

对比GBN和SR

GBN SR
优点 简单,所需资源少(接收方一个缓存单元) 出错时,重传一个代价小
缺点 一旦出错,回退N步代价大 复杂,所需要资源多(接收方多个缓存单元)
  • 适用范围
  • 出错率低:比较适合GBN,出错非常罕见,没有必要用复杂的SR,为罕见的事件做日常的准备和复杂处理
  • 链路容量大(延迟大、带宽大):比较适合SR而不是GBN,一点出错代价太大

窗口的最大尺寸(若整个的序号空间是 $2^n$

  • GBN: $2^n-1$ ,如 $n=2$$GBN=3$
  • SR: $2^{n-1}$ ,如 $n=2$$SR=2$
    • SR的例子:
      • 接收方看不到二者的区别!
      • 将重复数据误认为新数据(a)

3.5 面向连接的传输:TCP

3.5.1 段结构

TCP:概述 RFCs: 793, 1122, 1323, 2018, 2581

  • 向应用进程提供点对点的服务:
    • 一个发送方,一个接收方(单点到单点)
  • 可靠的、按顺序的字节流:
    • 没有报文边界,报文界限靠应用进程自己区分
  • 管道化(流水线):
    • TCP拥塞控制和流量控制设置窗口大小
  • 发送和接收缓存
    • 发送缓存区:发完后需要检错重发、超时重传
    • 接收缓存区:发送方的发送速率不等于接收方的接收速率,需要接收缓存区匹配速度的不一致性
  • 全双工数据:
    • 在同一连接中数据流双向流动(同时、双向)
    • MSS:最大报文段大小。TCP按照MSS进行报文段的切分,每个MSS报文段前加上TCP头部形成TCP报文段(IP header + TCP header + MSS = MTU(Maixum Transfer Unit, 最大传送单元,表示IP数据报的最大长度(不包括帧头尾),单位为字节))
  • 面向连接:
    • 在数据交换之前,先建立连接,通过握手(交换控制报文)初始化发送方、接收方的状态变量
  • 有流量控制:
    • 发送方不会淹没接收方

TCP报文段结构

注:这里第二行的“序号”不是前面讲的PDU的序号(不是分组号),而是字节的序号:body部分的第一个字节在整个字节流中的偏移量offset(第 $i$ 个MSS的第一个字节在字节流中的位置,初始的序号称为 $X$$X$ 在建立连接时两个进程商量好,第 $n$ 个的序号为 $X+n*MSS$

TCP序号,确认号

  • 序号(sequence number, 简写seq):
    • 报文段首字节的在字节流的编号
  • 确认号(acknowledgement number, 简写ack):
    • 期望从另一方收到的下一个字节的序号
    • 累积确认(如假设ack=555,则表示接收方已经收到了554及之前的所有字节)
  • Q:接收方如何处理乱序的报文段? 没有规定(可以缓存,也可以抛弃,取决于实现者自己)

例:Host A - Host B (双向数据传递)

  1. A(User types 'C') --> B(host ACKs receipt of 'C', echoes back 'C'): Seq = $42$ , ACK = $79$ , data = 'C';
  2. B(host ACKs receipt of 'C', echoes back 'C') --> A(host ACKs receipt of echoed 'C'): Seq = $79$ , ACK = $43$ , data = 'C';
  3. A(host ACKs receipt of echoed 'C') --> B: Seq = $43$ , ACK = $80$ , data = ...
  4. ...

TCP往返延时(RTT)和超时

  • Q:怎样设置TCP超时定时器?

    • 比RTT要长
      • 但RTT是变化的
    • 太短:太早超时
      • 不必要的重传
    • 太长:对报文段丢失反应太慢,消极
  • Q:怎样估计RTT?

    • SampleRTT:测量从报文段发出到收到确认的时间,得到往返延时
      • 如果有重传,忽略此次测量
    • SampleRTT会变化,因此估计的RTT应该比较平滑
      • 对几个最近的测量值求平均,而不是仅用当前的SampleRTT
  • RTT不是一个固定的值,而是一个适应式的测量。由于每个分组经历不一样,严重依赖于网络状况,则SampleRTT变化非常大,用SampleRTT建立超时定时器不合理,需要用SampleRTT的平均值EstimatedRTT(滤波算法)

    • $[EstimatedRTT] = (1-\alpha) * [(previous)EstimatedRTT] + \alpha * SampleRTT$
    • 指数加权移动平均
    • 过去样本的影响呈指数衰减
    • 推荐值: $\alpha = 0.125$
  • 设置超时

    • EstimtedRTT + 安全边界时间(safety margin)
    • EstimatedRTT变化大(方差大)
      • 较大的安全边界时间
    • SampleRTT会偏离EstimatedRTT多远:
      • $[DevRTT] = (1-\alpha) * [(previous)DevRTT] + \alpha * |SampleRTT-EstimatedRTT|$
      • 推荐值: $\alpha = 0.25$
  • 超时时间间隔设置为:

    • $TimeoutInterval = EstimatedRTT + 4*DevRTT$

3.5.2 可靠数据传输

TCP:可靠数据传输

  • TCP在IP不可靠服务的基础上建立了rdt
    • 管道化的报文段
      • GBN or SR
    • 累积确认,期望从另一方收到的下一个字节的序号,对顺序到来的最后一个字节给予确认(像GBN)
    • 单个重传定时器(像GBN),只和最老的段相关联,一旦超时就将最老的段重发一遍(像SR)
    • 是否可以接受乱序的,没有规范
  • 通过以下事件触发重传
    • 超时(只重发那个最早的未确认段:SR)
    • 重复的确认(又收到3个冗余确认)(又叫快速重传)
      • 例子:收到了ACK50,之后又收到3个ACK50
  • 首先考虑简化的TCP发送方:
    • 忽略重复的确认
    • 忽略流量控制和拥塞控制

TCP发送方事件:

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

TCP:重传

产生TCP ACK的建议 [RFC 1122, RFC 2581]

接收方的事件 TCP接收方动作
所期望序号的报文段按序到达。所有在期望序号之前的数据都已经被确认 延迟的ACK(提高效率,少发一个ACK)。对另一个按序报文段的到达最多等待500ms。如果下一个报文段在这个时间间隔内没有到达,则发送一个ACK。
有期望序号的报文段到达。另一个按序报文段等待发送ACK 立即发送单个累积ACK,以确认两个按序报文段。
比期望序号大的报文段乱序到达。检测出数据流中的间隔 立即发送重复的ACK,指明下一个期待字节的序号
能部分或完全填充接收数据间隔的报文段到达 若该报文段起始于间隔(gap)的低端,则立即发送ACK(给确认并反映下一段的需求)。

快速重传(3个冗余ACK触发的重发)

  • 超时周期往往太长:
    • 在重传丢失报文段之前的延时太长
  • 通过重复的ACK来检测报文段丢失
    • 发送方通常连续发送大量报文段
    • 如果报文段丢失,通常会引起多个重复的ACK
  • 如果发送方收到同一数据的3个冗余ACK,重传最小序号的段;
    • 快速重传:在定时器过时之前重发报文段
    • 它假设跟在被确认的数据后面的数据丢失了
      • 第一个ACK是正常的;
      • 收到第二个该段的ACK,表示接收方收到一个该段后的乱序段;
      • 收到第3,4个该段的ack,表示接收方收到该段之后的2、3个乱序段,有非常大的可能性为段丢失了

三重ACK接收后的快速重传

3.5.3 流量控制

目的:接收方控制发送方,不让发送方发送的太多、太快,超过了接收方的处理能力,以至于让接收方的接收缓冲区溢出

TCP流量控制

  • 接收方在其向发送方的TCP段头部的rwnd字段“通告”其空闲buffer大小

    • RcvBuffer大小通过socket选项设置(典型默认大小为4096字节)
    • 很多操作系统自动调整RcvBuffer
  • 发送方限制未确认(“in-flight”)字节的个数小于等于接收方发送过来的 rwnd 值

  • 保证接收方不会被淹没

  • 假设TCP接收方丢弃乱序的报文段,则缓存中的可用的空间: $RcvWindow = RcvBuffer - [LastByteRcvd - LastByteRead]$

3.5.4 连接管理

连接

  • 两个应用进程建立起的TCP连接
  • 连接的本质:
    • 双方知道要和对方通信
    • 为这次通信建立好缓冲区,准备好资源
    • 一些控制变量需要做置位,两者需要互相告知自己的初始序号,初始化的RcvBuffer

在正式交换数据之前,发送方和接收方握手建立通信关系:

  • 同意建立连接(每一方都知道对方愿意建立连接)
  • 同意连接参数

同意建立连接

  • Q:在网络中,2次握手建立连接总是可行吗?不行
    • 变化的延迟(连接请求的段没有丢,但可能超时)

    • 由于丢失造成的重传(e.g. req_conn(x))

    • 报文乱序

    • 相互看不到对方

    • 2次握手的失败场景:

解决方案:TCP 3次握手(变化的初始序号+双方确认对方的序号)

  • 第一次:client-->server:客户端一方的初始序号 $x$
  • 第二次:server-->client:发送确认 $ACKnum=x+1$ 和服务器一方的初始序号 $y$ (捎带)
  • 第三次:client-->server:发送确认 $ACKnum=y+1$ 和客户端data(捎带)

3次握手解决:半连接和接收老数据问题

  1. 二次握手:可能发送半连接(只在服务器维护了连接);三次握手:客户端在第三次握手拒绝连接请求 服务器二次握手后的连接请求
  2. 二次握手:老的数据被当成新的数据接收了;三次握手:未建立连接(无半连接),故将发来的数据丢掉(扔掉:连接不存在,没建立起来;连接的序号不在当前连接的范围之内)
  3. 若一个数据滞留时间足够长导致在TCP第二次连接(两个三次握手后)到来,这个数据包大概率也会被丢弃,因为初始序号seq不一样,而seq又与时间有关(时钟周期的第k位)

TCP:关闭连接(连接释放):4次挥手

  • 客户端,服务器分别关闭它自己这一侧的连接
    • 发送FIN bit = 1的TCP段
  • 一旦接收到FIN,用ACK回应
    • 接到FIN段,ACK可以和它自己发出的FIN段一起发送
  • 可以处理同时的FIN交换
  • “对称释放,并不完美”

假设Client端发起中断连接请求,也就是发送FIN报文。Server端接到FIN报文后,意思是说“我Client端没有数据要发给你了”,但是如果你还有数据没有发送完成,则不必急着关闭Socket,可以继续发送数据。所以你先发送ACK,告诉Client端:“你的请求我收到了,但是我还没准备好,请继续你等我的消息”。这个时候Client端就进入FIN_WAIT状态,继续等待Server端的FIN报文。当Server端确定数据已发送完成,则向Client端发送FIN报文,告诉Client端:“好了,我这边数据发完了,准备好关闭连接了”。Client端收到FIN报文后,就知道可以关闭连接了,但是他还是不相信网络,怕Server端不知道要关闭,所以发送ACK后进入TIME_WAIT状态,如果Server端没有收到ACK则可以重传。Server端收到ACK后,就知道可以断开连接了。Client端等待了2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,我Client端也可以关闭连接了。Ok,TCP连接就这样关闭了!

【问题1】为什么连接的时候是三次握手,关闭的时候却是四次握手?
答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,“你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

3.6 拥塞控制原理

拥塞:

  • 非正式的定义:“太多的数据需要网络传输,超过了网络的处理能力”
  • 与流量控制不同,流量控制是我到你的问题,拥塞控制是网络的问题
  • 拥塞的表现:
    • 分组丢失(路由器缓冲区溢出)
    • 分组经历比较长的延迟(在路由器的队列中排队)
  • 网络中前10位的问题!

拥塞的原因/代价:场景1

  • 2个发送端,2个接收端
  • 1个路由器,具备无限大的缓冲
  • 输出链路带宽: $R$
  • 没有重传
  • 每个连接的最大吞吐量: $R/2$ ;当进入的速率 $\lambda_{in}$ 接近链路链路带宽 $R$ 时,延迟增大(此时流量强度趋于1)

拥塞的原因/代价:场景2

  • 1个路由器,有限的缓冲
  • 分组丢失时,发送端重传
    • 应用层的输入=应用层输出: $\lambda_{in} = \lambda_{out}$
    • 传输层的输入包括重传: $\lambda_{in}^{'} \geq \lambda_{in}$,且当流量强度越趋于1, $\lambda_{in}^{'}$ 将比 $\lambda_{in}$ 大得多(很多都需要重传)

场景2:

  1. 理想化:发送端有完美的信息
  • 发送端知道什么时候路由器的缓冲是可用的
    • 只在缓冲可用时发送
    • 不会丢失:$\lambda_{in}^{'} = \lambda_{in}$
  1. 理想化:掌握丢失信息
  • 分组可以丢失,在路由器由于缓冲器满而被丢弃
  • 如果知道分组丢失了,发送方重传分组
  1. 现实情况:重复
  • 分组可能丢失,由于缓冲器满而被丢弃
  • 发送端最终超时,发送第2个拷贝,2个分组都被传出
  • 此时随着 $\lambda_{in}$ 的增大, $\lambda_{out}$ 也增大,但是由于超时重传的比例越来越大, $\lambda_{out}$ 越来越小于 $\lambda_{in}$
    • 输出比输入少原因:1)重传的丢失分组;2)没有必要重传的重复分组

拥塞的“代价”:

  • 延时大
  • 为了达到一个有效输出,网络需要做更多的泵入(重传)
  • 没有必要的重传,链路中包括了多个分组的拷贝
    • 是那些没有丢失,经历的时间比较长(拥塞状态)但是超时的分组,重发没有必要,对本就拥塞的网络雪上加霜(网络加速变坏,非线性)
    • 降低了的“goodput”

拥塞的原因/代价:场景3

  • 4个发送端
  • 多重路径
  • 超时/重传
  • Q:当 $\lambda_{in}^{'}$$\lambda_{in}$ 增加时,会发生什么?
    A:当红色的 $\lambda_{in}^{'}$ 增加时,所有到来的蓝色分组都在最上方的队列中丢弃了,蓝色吞吐->0

又一个拥塞的代价:当分组丢失时,任何“关于这个分组的上游传输能力”都被浪费了,严重时导致整个网络死锁

2种常用的拥塞控制方法:

  • 端到端拥塞控制(自身判断)
    • 没有来自网络的显式反馈
    • 端系统根据延迟和丢失事件自身推断是否有拥塞
    • TCP采用的方法
  • 网络辅助的拥塞控制(路由器反馈)
    • 路由器提供给端系统以反馈信息
      • 单个bit置位,显示有拥塞 (SNA, DECbit, TCP/IP ECN, ATM)
      • 显式提供发送端可以采用的速率

案例:ATM ABR 拥塞控制(网络辅助的拥塞控制)

ATM网络数据交换的单位叫 信元(一个小分组,53字节:5字节的头部+48字节的数据载荷)。

信元每个分组数据量较小,在每个交换节点存储-转发耽误的时间比分组交换小,且时间固定,便于调度。ATM网络集合了分组交换和线路交换的特性。

ATM虽然不是大众常用网络,但是在一些专用场合用处较大

ATM网络有很多模式,其中一个模式是ABR: available bit rate:

  • 提供“弹性服务”
  • 如果发送端的路径“轻载”不发生拥塞
    • 发送方尽可能地使用可用带宽(“市场调控”)
  • 如果发送方的路径拥塞了
    • 发送方限制其发送的速度到一个最小保障速率上(“配给制”)

ATM网络中的信元可以分为2种:大部分是数据信元,另一种为间或地插入到数据信元当中的资源管理信元。

RM(资源管理)信元:

  • 由发送端发送,在数据信元中间隔插入
  • RM信元中的比特被交换机设置(“网络辅助”)
    • NI bit: no increase in rate (轻微拥塞)速率不要增加了,轻微拥塞时设置为1
    • CI bit: congestion indication 拥塞指示,拥塞时设置为1
  • 发送端发送的RM信元被接收端返回,接收端不做任何改变
  • 在RM信元中的2个字节ER(explicit rate)字段
    • 拥塞的交换机可能会降低信元中ER的值
    • 发送端发送速度因此是最低的可支持速率
  • 数据信元中的EFCI bit:被拥塞的交换机设置成1
    • 如果在管理信元RM前面的数据信元EFCI被设置成了1,接端在返回的RM信元中设置CI bit

总结:网络提供一些信息,包括一些标志位的置位以及字段 (为两主机间的通信提供多大的带宽)

3.7 TCP拥塞控制

  • TCP拥塞控制采用端到端的拥塞控制机制
    • 路由器不向主机有关拥塞的反馈信息
      • 路由器的负担较轻
      • 符合网络核心简单的TCP/IP架构原则,网络核心提供最小的服务集
    • 端系统根据自身得到的信息,判断是否发生拥塞,从而采取动作
  • 拥塞控制的几个问题
    • 如何检测拥塞
      • 轻微拥塞
      • 拥塞
    • 控制策略
      • 在拥塞发送时如何动作,降低速率
        • 轻微拥塞,如何降低
        • 拥塞时,如何降低
      • 在拥塞缓解时如何动作,尽可能增加速率

拥塞感知:发送端如何探测到拥塞?

  • 某个段超时了(丢失事件):拥塞
    • 超时时间到,某个段的确认没有来
    • 原因1:网络拥塞(某个路由器缓冲区没空间了,被丢弃) 概率大
    • 原因2:出错被丢弃了(各级错误,没有通过校验,被丢弃) 概率小。此时不应该降低发送速率
    • 一旦超时,就认为拥塞了,有一定误判(原因2,但概率小),但是总体控制方向是对的
  • 有关某个段的3次重复ACK:轻微拥塞
    • 段的第1个ack,正常,确认绿段,期待红段
    • 段的第2个重复ack,意味着红段的后一段收到了,蓝段乱序到达
    • 段的第2、3、4个ack重复,意味着红段的后第2、3、4个段收到了,橙段乱序到达,同时红段丢失的可能性很大(后面3个段都到了,红段都没到)
    • 网络这时还能够进行一定程度的传输,拥塞但情况要比第一种好

速率控制方法:如何控制发送端发送的速率

  • 维持一个拥塞窗口的值:CongWin(以字节为单位,表示发送方在对方未确认的情况下往网络中注入多少字节)
  • 发送端限制已发送但是未确认的数据量(的上限): $$LastByteSent - LastByteAcked \leq CongWin$$
  • 从而粗略地控制发送方的往网络中注入的速率
  • CongWin是动态的,是感知到的网络拥塞程度的函数
    • 超时或者3个重复ack,CongWin下降
      • 超时:CongWin降为1MSS,进入SS阶段然后再倍增到CongWin/2(每个RTT),从而进入CA阶段
      • 3个重复ack:CongWin降为CongWin/2, CA阶段
    • 否则(正常收到Ack,没有发送以上情况):CongWin跃跃欲试(上升)
      • SS阶段(慢启动阶段):每经过一个RTT进行CongWin的加倍
      • CA阶段(拥塞避免阶段):每经过一个RTT进行1个MSS的线性增加

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

  • 联合控制的方法:
    • 发送端控制发送但是未确认的量同时也不能够超过接收窗口的空闲尺寸(接收方在返回给发送方的报文中捎带),满足流量控制要求
      • $SendWin = \min(CongWin, RecvWin)$
      • 同时满足 拥塞控制 和 流量控制 要求

TCP 拥塞控制:策略概述

  • 慢启动
    • 连接刚建立, $CongWin = 1MSS$
      • 如: $MSS = 1460bytes$ & $RTT = 200msec$
      • 则可计算得初始速率为 $MSS/RTT = 58.4kbps$ ,这是一个很小的速率,可用带宽可能远远大于它,应当尽快着手增速,到达希望的速率
    • 当连接开始时,指数性(后一次速率是前一次的2倍)增加发送速率,直到发生丢失的事件
      • 启动初值很低
      • 但是速度很快(指数增加,SS时间很短,长期来看可以忽略)
    • 当连接开始时,指数性增加(每个RTT)发送速率直到发生丢失事件
      • 每一个RTT,CongWin加倍
      • 每收到一个ACK时,CongWin加1(等价于每个RTT,CongWin翻倍)
      • 慢启动阶段:只要不超时或3个重复ack,一个RTT后CongWin加倍
  • AIMD:线性增、乘性减少
    • 乘性减:
      • 丢失事件后将CongWin降为1,将CongWin/2作为阈值,进入慢启动阶段(倍增直到CongWin/2)
    • 加性增:
      • 当CongWin>阈值时,一个RTT如没有发生丢失事件,将CongWin加1MSS:探测
    • 当收到3个重复的ACKs:(3个重复的ACK表示网络还有一定的段传输能力(轻微拥塞),超时之前的3个重复的ACK表示“警报”)
      • CongWin减半
      • 窗口(缓冲区大小)之后线性增长
    • 当超时事件发生时:
      • CongWin被设置成 1MSS,进入SS阶段
      • 之后窗口指数增长
      • 增长到一个阈值(上次发生拥塞的窗口的一半)时,再线性增加
  • 超时事件后的保守策略
    • Q:什么时候应该将指数性增长变成线性?
    • A:在超时之前,当CongWin变成上次发生超时的窗口的一半
    • 实现:
      • 变量:Threshold
      • 出现丢失,Threshold设置成CongWin的1/2

总结:TCP拥塞控制

  • 当CongWin < Threshold,发送端处于慢启动阶段(slow-start),窗口指数性增长。
  • 当CongWin > Threshold,发送端处于拥塞避免阶段(congestion-avoidance),窗口线性增长。
  • 当收到三个重复的ACKs(triple duplicate ACK),Threshold设置成CongWin/2,CongWin=Threshold+3。
  • 当超时事件发生时timeout,Threshold=CongWin/2,CongWin=1MSS,进入SS阶段

TCP 发送端拥塞控制

事件 状态 TCP 发送端行为 解释
以前没有收到ACK的data被ACKed 慢启动(SS) CongWin = CongWin + MSS
If (CongWin > Threshold)
状态变成 “CA”
每一个RTT,CongWin加倍
以前没有收到ACK的data被ACKed 拥塞避免(CA) CongWin = CongWin + MSS*(MSS/CongWin) 加性增加,每一个RTT对CongWin加一个1MSS
通过收到3个重复的ACK,发现丢失的事件 SS or CA Threshold = CongWin/2
CongWin = Threshold+3
状态变成“CA”
快速重传,实现乘性的减。
CongWin没有变成1MSS。
超时 SS or CA Threshold = CongWin/2
CongWin = 1MSS
状态变成“SS”
进入slow start
重复的ACK SS or CA 对被ACKed的segment,增加重复ACK的计数 CongWin and Threshold 不变

TCP 吞吐量

  • TCP的平均吞吐量是多少,使用窗口window尺寸W和RTT来描述?
    • 忽略慢启动阶段,假设发送端总有数据传输
  • 定义W为发生丢失事件时的窗口尺寸(单位:字节),则全过程在W/2和W之间变化
    • 平均窗口尺寸(#in-flight字节):3/4W
    • 平均吞吐量:RTT时间吞吐3/4W $$avg TCP thruput = \frac{3}{4} \frac{W}{RTT} bytes/sec$$

TCP公平性

  • 公平性目标:如果 $K$ 个TCP会话分享一个链路带宽为 $R$ 的瓶颈,每一个会话的有效带宽为 $R/K$
  • TCP为什么是公平的?
    • 考虑2个竞争的TCP会话:
      • 加性增加,斜率为1,吞吐量增加
      • 乘性减,吞吐量比例减少
  • 公平性和UDP
    • 多媒体应用通常不是用TCP
      • 应用发送的数据速率希望不受拥塞控制的节制
    • 使用UDP:
      • 音视频应用泵出数据的速率是恒定的,忽略数据的丢失
    • 研究领域:TCP友好性
  • 公平性和并行TCP连接
    • 2个主机间可以打开多个并行的TCP连接
    • Web浏览器
    • 例如:带宽为R的链路支持了9个连接
      • 如果新的应用要求建1个TCP连接,获得带宽R/10
      • 如果新的应用要求建11个TCP连接,获得带宽R/2

3.8 总结 & 展望

  • 传输层提供的服务
    • 应用进程间的逻辑通信
      • Vs 网络层提供的是主机到主机的通信服务
    • 互联网上传输层协议:UDP TCP
      • 特性
  • 多路复用和解复用
    • 端口:传输层的SAP
    • 无连接的多路复用和解复用
    • 面向连接的多路复用和解复用
  • 实例1:无连接传输层协议 UDP
    • 多路复用解复用
    • UDP报文格式
    • 检错机制:校验和
  • 可靠数据传输原理
    • 问题描述
    • 停止等待协议
      • Rdt 1.0, 2.0, 2.1, 2.2, 3.0
    • 流水线协议
      • GBN
      • SR(Selective Repeat)
  • 实例2:面向连接的传输层协议-TCP
    • 概述:TCP特性
    • 报文段格式
      • 序号,超时机制及时间
    • TCP可靠传输机制
    • 重传,快速重传
    • 流量控制
    • 连接管理
      • 三次握手
      • 对称连接释放
  • 拥塞控制原理
    • 网络辅助的拥塞控制
    • 端到端的拥塞控制
  • TCP的拥塞控制
    • AIMD
    • 慢启动
    • 超时之后的保守策略
  • 展望下2章:
    • 离开网络“边缘”(应用层和传输层)
    • 深入到网络的“核心”
    • 2个关于网络层的章
      • 数据平面
      • 控制平面