目标:
- 理解传输层的工作原理:多路复用/解复用;可靠数据传输RDT;流量控制;拥塞控制。
- 学习Internet的传输层协议:UDP、TCP、TCP的流量控制
3.1 概述和传输层服务
传输服务和协议
- 为运行在不同主机上的应用进程提供逻辑通信
- 传输协议运行在端系统
- 发送方:将应用层的报文分成报文段,然后传递给网络层
- 接收方:将报文段重组成报文,然后传递给应用层
- 有多个传输层协议可供应用选择 Internet: TCP和UDP
传输层VS网络层
- 网络层服务:主机之间的逻辑通信
- 传输层服务:进程之间的逻辑通信
- 依赖于网络层的服务:延时、带宽
- 并对网络层的服务进行增强:数据丢失、顺序混乱、加密
Internet传输层协议
可靠的、保序的传输:TCP 字节流
- 多路复用、解复用
- 拥塞控制
- 流量控制
- 建立连接
不可靠、不保序的传输:UDP 数据报
- 多路复用、解复用
- 没有为尽力而为的IP服务添加更多的其他额外服务
都不提供的服务:延时保证、带宽保证
3.2 多路复用/解复用
在发送方主机多路复用
从多个套接字接收来自多个进程的报文,根据套接字对应的IP地址和端口号等信息对报文段用头部加以封装(该头部信息用于以后的解复用)
在接收方主机多路解复用
根据报文段的头部信息中的IP地址和端口号将接收到的报文段发给正确的套接字(和对应的应用进程)

在目的主机, 运输层从紧邻其下的网络层接收报文段。 运输层负责将这些报文段中的数据交付给在主机上运行的适当应用程序进程。
一个进程(作为网络应用的一部分)有一个或多个套接字(socket) 。在接收主机中的运输层实际上并没有直接将数据交付给进程, 而是将数据交给了一个中间的套接字。 每个套接字都有唯一的标识符。 标识符的格式取决于它是UDP还是TCP套接字。
3.3 无连接传输:UDP
UDP特点
- 尽力而为的服务,报文段可能:丢失、送到应用进程的报文段乱序
- 无连接:UDP发送端和接收端之间没有握手、每个UDP报文段都被独立地处理
- UDP被用于:流媒体(丢失不敏感、速率敏感、应用可控制传输速率)、DNS、SNMP
- 在UDP上实现可靠传输:在应用层增加可靠性、应用特定的差错恢复
UDP:用户数据报协议
为什么叫数据报?
无连接,每个UDP的协议数据单元都是独立发送的,所以叫数据报。
IP也叫数据报,所以要结合上下文来看到底指哪个数据报。
UDP报文段结构

长度字段指示了在UDP报文段中的字节数(首部+数据)
检验和:EDC 接收方使用检验和判断整个报文段(包含首部、数据部分)有没有出错。如果出错,该数据报会被丢掉。
为什么要有UDP?
- 不建立连接(会增加延时)
- 简单:在发送端和接收端没有连接状态
- 报文段的头部很小(开销小)
- 无拥塞控制和流量控制:UDP可以尽可能快的发送报文段;
应用->传输的速率=主机->网络的速率
UDP校验和
目标:检测在被传输报文段中的差错(如比特反转)
发送方:
- 将报文段的内容视为16比特的整数
- 校验和:报文段的加法和(1的补运算)
- 发送方将校验和放在UDP的校验和字段
接收方:
- 计算接收到的报文段和校验和
- 检查计算出的校验和与校验和字段的内容是否相等:不相等—检测到差错;不相等—没有检测到差错,但也许还是有差错,残存错误。
进位回卷
目标端:校验范围+校验和=1111111111111111通过校验
3.4 可靠数据传输的原理
可靠数据传输(rdt)的原理
reliable data transfer protocol rdt在应用层、传输层和数据链路层都很重要,是网络TOP10问题之一
信道的不可靠特点决定了可靠数据传输协议(rdt)的复杂性

RDT1.0:在可靠信道上的可靠数据传输
下层的信道是完全可靠的:没有比特出错;没有分组丢失
发送方和接收方的FSM:发送方将数据发送到下层信道;接收方从下层信道接收数据。
RDT2.0:具有比特差错的信道

RDT2.0的致命缺陷!->RDT2.1
如果ACK/NAK出错?
发送方不知道接收方发生了什么事情,发送方如何做?重传?可能重复;不重传?可能死锁(出错);
引入新的机制:序号
接收方可以通过序号判断是否是重复的请求
处理重复:发送方在每个分组中加入序号,如果ACK/NAK出错,发送方重传当前分组,接收方丢弃(不发给上层)重复分组。
停止等待协议:发送方发送一个分组,然后等待收方的应答。
讨论:
发送方:
- 在分组中加入序列号,两个序列号(0,1)就足够了,一次只发送一个未经确认的分组
- 必须检测ACK/NAK是否出错(需要EDC)
- 状态数变成了两倍,必须记住当前分组的序列号是0还是1
接收方:
- 必须检测接收到的分组是否是重复的,状态会指示希望接收到的分组的序号是0还是1
- 接收方并不知道发送方是否正确接收到了ACK/NAK
RDT2.2 出错返回上一条请求的正向回复
高情商的回复
发送消息1,收到ACK1;
发送消息2,又收到ACK1,说明消息2发送失败了,重发消息2
RDT 3.0 具有比特差错和分组丢失的信道
新的假设:下层信道可能会丢失分组(数据或ACK),会导致死锁、机制还不够处理这种状况。
方法:发送方等待ACK一段合理的时间
- 发送端超时重传:如果到时没有收到ACK->重传
- 问题:如果分组(或ACK)只是被延迟了:重传会导致数据重复,但利用序列号已经可以处理这个问题;接收方必须指明被正确接收的序列号
- 需要一个倒计数定时器
RDT3.0的性能
RDT3.0是一个比较完备的协议,但是在链路信道容量比较大的情况下,性能很差。链路容量比较大。一次发一个PDU的不能够充分利用链路的传输能力(应该用下面的流水线协议)
停止等待协议在局域网场景下适用,因为往返延迟比较小、链路容量小,适合一次发一个PDU。


流水线协议
pipeline协议
允许发送方在未得到对方确认的情况下一次发送多个分组。
- 需要增加序号的范围:用多个bit表示分组的序号
- 在发送方、接收方需要有缓冲区:
- 发送方缓冲:未得到确认,可能需要重传
- 接收方缓存:上层用户取用数据的速率不等于接收到的数据速率;接收到的数据可能扰乱顺序。排序交付(可靠)
两种通用的流水线协议:回退N步(GBN)和选择重传(SR selective repeat)
滑动窗口协议
发送缓冲区:
发送缓冲区≠发送窗口
形式:内存中的一个区域,落入缓冲区的分组可以发送
功能:用于存放已发送,但是没有得到确认的分组
必要性:需要重发时可用
发送缓冲区的大小:一次最多可以发送多少个未经确认的分组
- 停止等待协议=1
- 流水线协议>1,合理的值,但不能很大,链路利用率不能超过100%
发送缓冲区中的分组
- 未发送的:落入发送缓冲区的分组,可以连续发送出去;
- 已经发送出去的,等待对方确认的分组:发送缓冲区的分组只有得到确认才能删除。
接收缓冲区:
接收窗口=接收缓冲区
接收窗口用于控制那些分组可以接收:
- 只有收到的分组序号落入接收窗口内才允许接收
- 若序号在接收窗口之外,则丢弃
接收窗口尺寸Wr=1,则只能顺序接收(GBN);接收窗口尺寸Wr>1(SR),则可以乱序接收,但是提交给上层的分组要排序
滑动:
- 低序号的分组到来,接收窗口移动;
- 高序号分组乱序到,比如4到了但是3还没到,缓存但不交付(因为要实现RDT,不允许失序),不滑动。
发送确认:
- GBN,接收窗口尺寸=1,使用累积确认,对顺序到来的最高分组进行确认,比如返回ACK3表示3及之前的分组都已经收到。
- SR,接收窗口尺寸>1,使用独立确认,收到分组,就发送那个分组的确认。
正常情况下发送窗口和接收窗口的互动
发送窗口:
- 有新的分组落入发送缓冲区,发送->前沿滑动
- 来了老的低序号分组的确认->后沿向前滑动->新的分组可以落入发送缓冲区的范围
- 发送窗口是发送缓冲区的子集
接收窗口:
- 收到分组,落入到接收窗口范围内,接收
- 是低序号,发送确认给对方
发送端上面来了分组->发送窗口滑动->接收窗口滑动->发确认——->发送窗口滑动
异常情况下GBN和SR两种
大概100分钟之后开始讲
SR108分钟
GBN和SR协议的异同
相同之处:
- 发送窗口>1
- 一次能够发送多个未经确认的分组
不同之处:
- GBN:接收窗口尺寸=1
- 接收端只能顺序接收
- 发送端:从表现来看,一旦一个分组没有发送成功,如:0,1,2,3,4;加入1未成功,234都发出去了,要返回1再全部重新发送
- SR:接收窗口尺寸>1
- 接收端:可以乱序接收
- 发送端:发送0,1,2,3,4;一旦1未发送成功,234已经发送,无需重发,选择性发送1
流水线协议总结
Go-back-N:
- 发送端最多在流水线中有N个未确认的分组
- 接收端只是发送累计型确认cumulative ack;接收端如果发现gap,不确认新到来的分组
- 发送端拥有对最老的未确认分组的定时器
- 只需设置一个定时器
- 当定时器到时时,重传所有未确认分组
Selective Repeat:
- 发送端最多再流水线中有N个未确认的分组
- 接收方对每个到来的分组单独确认individual ack(非累计确认)
- 发送方为每个未确认的分组保持一个定时器
- 当超时定时器到时,只是重发到时的未确认分组
对比GBN和SR
| GBN | SR | |
|---|---|---|
| 优点 | 简单,所需资源少(接收方一个缓存单元) | 出错时,重传一个代价小 |
| 缺点 | 一旦出错,回退N步代价大 | 复杂,所需资源多(接收方多个缓存单元) |
适用范围
- 出错率低:比较适合GBN,出错非常罕见,没有必要用复杂的SR,为罕见的事件做日常的准备和复杂的处理
- 链路容量大(延迟大、带宽大):比较适合SR而不是GBN,一旦出错代价太大。
3.5 面向连接的传输:TCP
概述
点对点:一个发送方,一个接收方
可靠的、按顺序的字节流:没有报文边界
管道化(流水线):TCP拥塞控制和流量控制设置窗口大小
发送和接收缓存
全双工数据:在同一连接中数据流双向流动;
MSS:最大报文段大小
面向连接:在数据交换之前,通过握手(交换控制报文)初始化发送方、接收方的状态变量
有流量控制:发送方不会淹没接收方
TCP报文段结构

- 32比特的序号字段和32比特的确认号字段。这些字段被TCP发送方和接收方用来实现可靠数据传输服务。
序号:报文段首字节的在字节流的编号
确认号: 期望从另一方收到的下一个字节的序号;累计确认
- 16比特的接收窗口字段,用于流量控制,该字段用于指示接收方愿意接受的字节数量。
- 紧急数据指针是一个古老的字段,没怎么用。
TCP往返延时(RTT)和超时
TCP超时不是一个固定的值,是一个不断适应的计算值。
问题:怎样设置TCP超时?
- 比RTT要长,但RTT是变化的;
- 不能太短:太早超时会带来不必要的重传
- 不能太长:对报文段丢失反应太慢,消极
问题:怎样估计RTT?
- SampleRTT:测量从报文段发出到收到确认的时间,如果有重传,忽略此次测量
- SampleRTT会变化,因此估计的RTT应该比较平滑,对几个最近的测量值求平均,而不是仅仅使用当前的SampleRTT
EstimatedRTT=(1-a)EstimatedRTT+asampleRTT; 推荐值a=0.125;
设置超时
TCP:可靠数据传输
TCP在不可靠服务的基础上建立了rdt
- 管道化的报文段:GBN or SR
- 累积确认(像GBN)
- 单个重传定时器(像GBN),但是不会全部重传,只重传一个最老的未确认的
- 是否可以接受乱序的,没有规范
通过以下事件触发重传:
- 超时(只重发那个最早的未确认段:SR)
- 重复的确认:例子,收到了ACK50之后又收到3个ACK50
首先考虑简化的TCP发送方:
- 忽略重复的确认
- 忽略流量控制和拥塞控制
TCP发送方事件
从应用层接收数据:
- 用nextseq创建报文段
- 序号nextseq为报文段首字节的字节流编号
- 如果还没有运行,启动定时器
- 定时器与最早未确认的报文段关联
- 过期间隔:TimeOutInterval
超时:
- 重传后沿最老的报文段
- 重新启动定时器
收到确认:

产生TCP ACK建议

快速重传

流量控制
接收方控制发送方,不让发送方发送的太多,太快以至于让接收方的缓冲区溢出。
接收方在其向发送方的TCP段头部的rwnd字段“通告”其空闲Buffer大小
- RevBuffer大小通过socket选项设置
- 很多操作系统自动调整RevBuffer
发送方限制未确认(“in-flight”)字节的个数≤接收方发送过来的rwnd值
保证接收方不会被淹没
TCP连接管理
TCP:建立连接 三次握手
在正式交换数据之前,发送方和接收方握手建立通信关系:
第一步: 客户端的TCP首先向服务器端的TCP发送一个特殊的TCP报文段。 该报文段中不包含应用层数据。 但是在报文段的首部中的一个标志位(即SYN比特) 被置为1。 因此, 这个特殊报文段被称为SYN报文段。
第二步: 一旦包含TCP SYN报文段的IP数据报到达服务器主机(假定它的确到达了!),服务器会从该数据报中提取出TCP SYN报文段, 为该TCP连接分配TCP缓存和变量, 并向该客户TCP发送允许连接的报文段。
第三步: 在收到SYNACK报文段后, 客户也要给该连接分配缓存和变量。 
一旦完成这3个步骤, 客户和服务器主机就可以相互发送包括数据的报文段了。 在以后每一个报文段中, SYN比特都将被置为0。
为什么要3次握手?
三次握手的目的是建立可靠的通信信道,说到通讯,简单来说就是数据的发送与接收,而三次握手最主要的目的就是双方确认自己与对方的发送与接收是正常的。
第一次握手:Client 什么都不能确认;Server 确认了对方发送正常,自己接收正常
第二次握手:Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:对方发送正常,自己接收正常
第三次握手:Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:自己发送、接收正常,对方发送、接收正常
所以三次握手就能确认双发收发功能都正常,缺一不可。
2次握手为什么不行?
半连接:如果服务器发送确认连接ACK超时,客户端会向服务器重传连接请求,因为是重复的请求,服务器不会确认。那么可能会产生虚假的半连接,该连接只有服务器在维护并没有用上,消耗资源。
接收老数据:
TCP:关闭连接 四次挥手

客户应用进程发出一个关闭连接命令, 客户TCP向服务器进程发送一个特殊的TCP报文段(首部中的一个标志位即FIN比特被设置为1)。当服务器接收到该报文段后, 就向发送方回送一个确认报文段。 然后, 服务器发送它自己的终止报文段, 其FIN比特被置为1, 最后该客户对这个服务器的终止报文段进行确认。 此时, 在两台主机上用于该连接的所有资源都被释放了。
将一组连接看作两个半连接,需要分别拆除。
存在“两军问题”,不可靠,可能存在一方拆除连接另一方还保持着的情况。(依靠定时器得以解决,如上图)。当连接结束后,主机中的“资源” (即缓存和变量) 将被客户释放。
客户TCP发送一个带有FIN比特被置为1的TCP报文段, 并进入FIN_WAIT_1状态。 当处在FIN_WAIT_1状态时, 客户TCP等待一个来自服务器的带有确认的TCP报文段。 当它收到该报文段时, 客户TCP进入FIN_WAIT_2状态。 当处在FIN_WAIT_2状态时, 客户等待来自服务器的FIN比特被置为1的另一个报文段; 当收到该报文段后, 客户TCP对服务器的报文段进行确认, 并进入TIME_WAIT状态。 假定ACK丢失, TIME_WAIT状态使TCP客户重传最后的确认报文。 在TIME.WAIT状态中所消耗的时间是与具体实现有关的, 而典型的值是30秒、 1分钟或2分钟。 经过等待后, 连接就正式关闭, 客户端所有资源(包括端口号) 将被释放。
3.6 拥塞控制原理
拥塞控制原理
拥塞:
(网络中前10的问题)
非正式的定义:太多的数据需要网络传输,超过了网络的处理能力
与流量控制不同
拥塞的表现:①分组丢失(路由器缓冲区溢出)②分组经历比较长的延迟(在路由器的队列中排队)
拥塞产生的原因/代价
一个路由器:有限的缓冲
分组丢失时,发送端重传:
- 应用层的输入=应用层输出:λin=λout
- 传输层的输入包括重传:λin’≥λin

理想情况:
(1)不丢失:发送端知道什么时候路由器的缓冲是可用的,那样只在缓冲可用的时候发送,λin’=λin
(2)可丢失:发送端知道分组丢失信息,发送方重传分组。
但针对第二种情况:λin’是传入速率,λout是有效输出速率。λin’逐渐接近R/2时,λout提升但是提升斜率小于1,因为λin’中重传所占的比例越来越高。
代价:为了能够达到有效的输出,λin’需要比λout要高许多。λin’越高延迟越大,导致更多的无谓的超时重传。
现实情况:
(1)分组可能丢失,由于缓冲器满而丢失
(2)发送端最终超时,发送第2个拷贝,2个分组都传到
拥塞的“代价”:
(1)为了达到一个有效输出,网络需要做更多的工作(重传)。
(2)没有必要的重传,链路中包含多个分组的拷贝。是那些没有丢失,但是经历的时间比较长(拥塞状态)超时了的分组,降低了“goodput”
四个路由器(上下左右) A->C 经历两跳。
在上面那个路由器,红色的流量强于蓝色的流量,因为蓝色的流量是经过左边路由器过滤后才到达上面路由器的。拥塞的时候,蓝色的流量会被红色的挤占。同理在右边的路由器,绿色和红色的会互相挤占。那么网络中会不断有输入的流量,但是输出的流量很少,就会拥塞甚至死锁。
那么又会产生一种新的“拥塞代价”:
当分组丢失时,任何“关于这个分组的上游传输能力”都被浪费了。
拥塞控制方法:
2种常用的拥塞控制方法:
端到端拥塞控制:
- 没有来自网络的显示反馈
- 端系统根据延迟和丢失事件判断是否有拥塞
- TCP采用的方法
网络辅助的拥塞控制:
路由器提供给端系统以反馈信息
- 单个bit置位,显示有拥塞(SNA,DECbit,TCP/IP ECN,ATM)
- 显式提供发送端可以采用的速率
案例学习:ATM ABR拥塞控制
ABR: Available Bit Rate
“弹性服务”,在不拥塞的情况下尽可能地提高发送速率
- 如果发送端的路径“轻载”,发送方使用可用带宽
- 如果发送方的路径拥塞了,发送方限制其发送的速度到一个最小保障速率上
RM(资源管理)单元
- 由发送端发送,在数据信元中间隔插入
- RM信元中的比特被交换机设置(“网络辅助”)
- NI bit: no increase in rate(轻微拥塞)速率不要增加了
- CI bit: congestion indication 拥塞指示
- 发送端发送的RM信元被接收端返回,接收端不做任何改变
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 ≤ CongWin
从而粗略地控制发送方的往网络中注入的速率
CongWin是动态的,是感知到的网络拥塞程度的函数
- 超时或者3个重复ack,CongWin减少
- 超时时:CongWin降低为1MSS,进入SS阶段然后再倍增到CongWin/2(每个RTT),从而进入CA阶段
- 3个重复ACK:CongWin降低为CongWin/2,CA阶段
- 否则(正常收到ACK,没有发生上面情况),CongWin跃跃欲试:
- SS阶段:加倍增加(每个RTT)
- CA阶段:线性增加(每个RTT)
MSS 最大报文段大小
CA 拥塞避免阶段
SS 慢启动阶段
拥塞控制策略:慢启动;AIMD:线性增、乘性减;超时事件后的的保守策略
慢启动:启动初值很低(CongWin=1MSS)但是加速确实指数性的,SS时间很短,长期来看可以忽略
注意:AIMD在丢失事件后(拥塞),做一个标记,记录警戒值(警戒值=拥塞值/2),将CongWin降低为1(1MSS),倍增,在走到警戒值的之后逐渐+1。再次丢失,记录新的警戒值,再次将CongWin降低为1。
如果是走到CA阶段(3个冗余ACK),不会回到CongWin=1,而是直接降一半。然后再进入拥塞避免阶段。


TCP发送端拥塞控制:
第3章 总结
传输层提供的服务:
- 应用进程间的逻辑通信
- 互联网上传输层协议:UDP TCP
多路复用和解复用
- 端口:传输层的SAP
- 无连接的多路复用和解复用
- 面向连接的多路复用和解复用
实例1:无连接传输层协议UDP
- 多路复用解复用
- UDP报文格式
- 检错机制:校验和
可靠数据传输原理:
- 问题描述
- 停止等待协议:rdt1.0 rdt2.0 rdt2.1 rdt2.2 rdt3.0
- 流水线协议:DBN SR
实例2:面向连接的传输层协议-TCP
- 概述:TCP特性
- 报文段格式:序号,超时机制及时间
- TCP可靠传输机制
- 重传,快速重传
- 流量控制
- 连接管理:三次握手、对称连接释放
拥塞控制原理:
- 网络辅助的拥塞控制
- 端到端的拥塞控制
TCP的拥塞控制:
- AIMD
- 慢启动
- 超时之后的保守策略


