# 概述运输层服务
运输层为运行在不同主机上的应用进程提供直接的通信服务。
运输层协议是在端系统中而不是在路由器中实现的。具体实现过程如下:
-
发送端:运输层将从发送应用程序进程接收到的报文转换成运输层分组,即运输层报文段(先将应用报文划分成小块,再加上运输层首部)。运输层将这些报文段发送给网络层,网络层将其封装成网络分组(即数据报)并向目的地发送。网络路由器只作用于数据报的网络层字段,而不检查封装在该数据报运输层报文段的字段。
-
接收端:网络层从数据报中提取运输层报文段并将该报文段向上交给运输层。
# 运输层和网络层的关系
网络层提供主机间的逻辑通信,运输层为运行在不同主机上的进程之间提供逻辑通信。
在端系统中运输层协议将来自应用进程的报文移动到网络边缘(即网络层)。
计算机网络中可以安排多种运输层协议,每种协议为应用程序提供不同的服务模型。
运输层协议能够提供的服务尝尝受制于底层网络层协议的服务模型。
即使网络层不能保证运输层报文段的机密性,运输协议也能使用加密来确保应用程序报文不被入侵者读取。
# 运输层概述
UDP(用户数据报协议):提供不可靠、无连接的服务,只能提供数据交付和差错检查。
TCP(传输控制协议):提供可靠的、面向连接的服务。
# 多路复用与多路分解
一个进程有一个或多个套接字(ip + 端口号),接收主机怎样将一个到达的运输层报文段定向到适当的套接字?
多路分解:在接收端,运输层检查这些字段,标识出接收套接字,进而将报文段定向到该套接字。将运输层报文段中的数据交付到正确的套接字的工作称为多路分解。
多路复用:在源主机从不同套接字中收集数据块,并为每个数据块封装上首部信息从而生成报文段,然后将报文段传递到网络层,这所有的工作称为多路复用。
运输层报文段的结构:

应用程序的客户端让运输层自动地分配端口号,服务器端则分配一个特定的端口号。
UDP 套接字由一个二元组全面标识,该二元组包含一个目的 ip 和一个目的端口号。
TCP 套接字由一个四元组全面标识,该四元组包含源 ip 地址、源端口号、目的 ip 地址、目的端口号。
# UDP 和 TCP 对比
# 无连接运输:UDP
UDP 优点:
- 关于发送什么数据以及何时发送的应用层控制更为精细(没有拥塞控制机制),按需随时发送。
- 无需建立连接,不会引入建立连接的时延。
- 无连接状态,TCP 维护连接状态需要维护包括接收和发送缓存、拥塞控制参数、序号与确认号的参数,而 UDP 不需要,因此当应用程序运行在 UDP 上,某些专门用于某种特定应用的服务器一般都能支持更多的活跃用户。
- 首部开销小。UDP:8Byte,TCP:20Byte
但是因为 UDP 没有拥塞控制,所以如果网络进入拥塞状态,UDP 的高丢包率会引起 TCP 的发送方大大减小它们的速率。
采用 UDP 的应用:
- 远程文件服务器(NFS)
- 流式多媒体
- 因特网电话
- 网络管理(SNMP)
- 选路协议(RIP)
- 域名解析(NDS)
UDP 报文段:

UDP 首部有 4 个字段,每个字段由两个字节组成。
长度:首部 + 数据。
接收方通过检验和检查该报文段是否出现问题。
UDP 检验和:
- 将报文段切成 16bit 的数据
- 对报文段中所有 16 比特字的和进行反码运算,求和时任何溢出都被回卷(进的位回到个位)
- 因为原码 + 反码 = 全 1,所以检查是否为全 1 即可
# 可靠数据传输原理
rdt1.0~rdt3.0 都使用停等协议
停等协议:发送方发送数据后等待接收方的响应
# 经完全可靠的信道的可靠信息传输:rdt1.0
底层信道完全可靠。
有限状态机(FSM)
因为底层信道完全可靠,所以接收方不需要反馈信息给发送方。
# 经具有比特差错信道的可靠数据传输:rdt2.x
2.x 解决了流控问题
底层信道分组中的比特可能受损。
# 2.0 发送的数据受损
采用自动重传请求协议(ARQ),进行差错检测、接收方反馈(ACK/NAK)、重传
重传:使用缓冲区缓存已发出但未收到反馈的报文段
# 2.1 ACK/NAK 受损
发送方不知道接收方的情况,只能重传。
但是可能导致接收方的重复接收,那么接收方怎么知道收到的分组是新的还是一次重传?于是引入分组编号。
因为只有两种状态:新的分组或者重传,所以只需要编号 0 和 1。如果收到的分组和上一次收到的分组编号一致,说明是一次重传
# 2.2 使用一个无 NAK 的可靠数据传输协议
重复的 ACK = NAK:不发送 NAK,而是对上次正确接收的分组发送一个 ACK;即当发送方接收到冗余的 ACK,就知道接收方没有正确接收到跟在被确认两次的分组后的分组。
# 经具有比特差错的丢包信道的可靠数据传输:rdt3.0
除了比特受损外,底层信道还会丢包。
设置倒计数定时器,面对超时的数据进行重传。如果数据本身未丢失只是超时了,就会导致冗余数据分组,直接忽略即可。
# 流水线可靠数据传输协议
因为 rdt3.0 使用的是停等协议,所以效率较低,于是使用流水线技术。
允许发送方发送多个分组并无需等待确认
- 原本的两个序号(0,1)不够用,必须增大序号范围
- 发送方最低限度应能缓存那些已发送但未被确认的分组
- 接收方需缓存那些已经正确接收的分组
当流水线技术中丢失一个分组,差错恢复有两种方法:回退 N 步和选择重传。
# 回退 N 步协议(GBN)
累计确认 ACK (n):接收方对序号 n 之前包括 n 在内的所有分组进行确认
超时事件:发送方重传所有已发送但未被确认的分组,发送方只使用一个定时器,如果收到一个 ACK 但是仍有已发送但未被确认的分组,则定时器被重新启动。
分组失序:接收方无缓存,所以直接丢弃,重发按序到达的最高序号后面的分组
滑动窗口大小:
# 选择重传(SR)
发送方:
- 从上层收到数据:如果下一个可用于该分组的序号在窗口内,则将数据打包并发送。
- 超时(n):为每个分组定义定时器;重传分组 n,重置定时器
- 收到确认(n)在 范围内:标记分组 n 为已接收,如果 n 是发送方窗口基序号 sendbase,则将窗口基序号推到下一个未确认序号
接收方:
- 分组序号 n 在 范围内
- 发送 n 的确认 ACK(n)
- 如果分组序号失序,将其缓存
- 按序分组:将该分组以及以前的缓存的序号连续的分组一起交付给上层,将窗口前推到下一个未收到的分组。
- 再次发送 n 的确认 ACK
- 其他情况,忽略该分组
接收方窗口 ****,即窗口的长度必须小于等于序号空间大小的一半
# 面向连接的运输:TCP
# TCP 的特点
面向连接:必须相互发送某些预备报文段,以建立确保数据传输的参数。
全双工服务:可双向同时传输数据。
点对点连接:仅能存在于两个端系统之间。
三次握手:客户端先发送一个特殊的 TCP 报文段,服务器用一个特殊的报文段进行响应,这两个报文段都不含应用层数据;最后客户端用第三个特殊报文段作为响应,第三个报文段可以承载有效数据。
可靠的字节流:TCP 可以从缓存中取出并放入报文段中的数据数量受限于最大报文段长度 MSS,MSS 由本地发送主机发送的最大链路层帧长度【即最大运输单元 MTU】设置。MSS 要保证加上 TCP/IP 首部长度(通常是 40 字节)将适合单个链路层帧。
注意:MSS 是指报文段中应用层数据的最大长度,而不是指包括首部的 TCP 报文段的最大长度。
# TCP 报文段结构
源端口和目的端口:各占 2 字节,端口是应用层和运输层的服务端口。运输层的复用和分解都需要通过端口实现。
序号:占 4 字节,TCP 连接中传输的数据流的每一个字节都有一个序号,序号字段的值指的是本报文段所发送的数据的第一个字节在整个报文字节流中的序号。
确认号:占 4 字节,是期望收到对方的下一个报文段的数据段的第一个字节的序号。
首部长度:占 4bit,该字段指示了以 32bit 的字为单位的 TCP 首部长度。(通常选项字段为空,TCP 首部典型长度是 20 字节)
保留字段:占 6bit,保留为今后使用,但目前应置为 0。
URG:紧急比特,UGR=1 表明此报文段中有紧急数据,应尽快送达。
ACK:确认 ACK,只有当 ACK=1 时确认号字段才有效;ACK=0 时,确认号无效。
PSH:接收到 PSH=1 的报文段,就尽快交付给接收应用进程,而不再等到整个缓存都填满再向上交付。
RST:当 RST=1 时,表名 TCP 连接中出现严重差错,必须释放连接,然后再重新建立运输链接。
SYN:同步比特,SYN=1,这是一个连接请求或连接接收的报文。
FIN:释放一个链接,当 FIN=1,此报文段的发送端的数据已经发送完毕,并要求释放运输链接。
窗口:占 2 字节,窗口字段用来控制对方发送的数据量,单位为字节。
检验和:占 2 字节,检验范围包括首部和数据两部分,计算时要在 TCP 报文段的前面加上 12 字节的伪首部。
紧急指针:占 2 字节,指出本报文段中紧急数据的最后一个字节的序号。
填充:为了使整个首部的长度是 4 字节的整数倍。
# 估计往返时间 RTT
在任意时刻,仅为一个已发送但目前尚未被确定的报文段估计 SampleRTT,从而产生一个接近每个 RTT 的新的 SampleRTT。
TCP 不为已被重传的报文段计算 SampleRTT。
因为 RTT 有波动,所以利用加权平均值计算 EstimatedRTT
估算 SampleRTT 偏离 EstimatedRTT 的程度:
第一次计算时
TCP 中确定重传超时间隔的方法:
推荐初始的
出现超时
# 可靠数据传输
TCP 使用单一定时器。
从上面应用程序收到数据 e:如果当前定时器没有运行,启动定时器并向 IP 传递报文段。
定时器超时:重传具有最小序号但仍未应答的报文段并启动定时器。
收到 ACK,具有 ACK 字段值 y:如果 y > SendBase
,重置 Sendbase = y
,如果仍有尚未确认的报文段,启动定时器。
(SendBase 是最早未被确认的字节的序号,SendBase - 1 是指接收方已正确按序接收到的数据的最后一个字节的序号)
超时间隔加倍:每次超时时间发生,TCP 重传时都会将下一次的超时时间间隔设为先前的两倍。
快速重传:当 TCP 接收方检测到了数据流中的一个间隔,就会不断重发它期望的这个 ACK,当冗余 ACK 的数量达到 3 的时候,就采用快速重传机制,在超时之前就重传该分组。
# 流量控制
接收方在反馈时,将缓冲区剩余空间的大小填充在报文段首部的窗口字段中,通知发送方
主机 A 向主机 B 发送文件,主机 B 接收缓存的大小是 RcvBuffer;主机 B 上的应用进程从缓存读出的数据流的最后一个字节的编号是 LastByteRead;从网络中到达的并且已放入主机 B 接收缓存中的数据流的最后一个字节的编号。
接收窗口的大小:
为让发送方在接收方的缓存满了之后可以及时了解什么时候又有新的空间,发送方持续向接收方发送只有一字节数据的报文段。
# TCP 连接管理
3 次握手,4 次分手
# 拥塞控制协议
拥塞控制方法:
网络辅助的拥塞控制
-
直接网络反馈:路由器以阻塞分组的形式通知发送方 “网络拥塞了”
-
经由接收方的网络反馈:路由器标识从发送方流向接收方分组中的某个字段以指示拥塞的产生,由接收方通知发送方 “网络拥塞了”(至少要经过一个完整的往返时间)
端到端拥塞控制
-
网络层不为拥塞控制提供任何帮助和支持
-
端系统通过对网络行为(丢包或时延增加)的观测判断网络是否发生拥塞
-
目前 TCP 采用该种方法(通过三个冗余的 ACK 实现)
# TCP 拥塞控制
# Reno 算法
加性增,乘性减(AIMD)
-
出现丢包事件后将当前 CongWin 大小减半,可以大大减少注入到网络中的分组数
-
当没有丢包事件发生了,每个 RTT 之后将 CongWin 增大 1 个 MSS,使拥塞窗口缓慢增大,以防止网络过早出现拥塞
# 慢启动和拥塞避免
建立连接时,CongWin = 1 MSS
eg:
- MSS(最大报文段大小) = 500 字节
- CongWin = 1 MSS = 500 字节 = 500 * 8 比特
- RTT = 200 毫秒
所以
可用带宽 >> MSS/RTT
-
初始阶段以指数的速度增加发送速率
-
连接初始阶段,以指数的速度增加发送速率,直到发生一个丢包事件为止
-
每收到一次确认则将 CongWin 的值增加一个 MSS

对收到 3 个重复 ACK 的反应
-
将 CongWin 减为原来的一半
-
线性增大拥塞窗口
对超时事件的反应
-
门限值设为当前 CongWin 的一半(门限值初始值 65kB)
-
将 CongWin 设为 1 个 MSS 大小;
-
窗口以指数速度增大
-
窗口增大到门限值之后,再以线性速度增大
- 当 TCP 连接进行初始化时,将拥塞窗口置为 1。图中的窗口单位不使用字节而使用报文段。慢开始门限的初始值设置为 16 个报文段,即 ssthresh = 16。
- 发送端的发送窗口不能超过拥塞窗口 cwnd 和接收端窗口 rwnd 中的最小值。我们假定接收端窗口足够大,因此现在发送窗口的数值等于拥塞窗口的数值。
- 当拥塞窗口 cwnd 增长到慢开始门限值 ssthresh 时(即当 cwnd = 16 时),就改为执行拥塞避免算法,拥塞窗口按线性规律增长。
# 快速恢复
-
3 个冗余 ACK 进入快速重传后
-
每收到一个冗余 ACK:CongWin++
-
直至收到一个新的 ACK:CongWin = 门限值,重新进入拥塞避免;因为已经收到了三个冗余 ACK,所以实际 cwnd = 门限值 + 3
-
在进入快速恢复之后及重新进入拥塞避免之间,如果出现超时现象,直接按照前述超时事件进行处理
总结
# TCP 吞吐量
假定当丢包事件发生时,窗口大小为 W,此时吞吐量为 W/RTT
丢包事件发生后,窗口大小减为 W/2, 吞吐量为 W/2RTT,因此平均吞吐量为: 0.75 W/RTT
吞吐量是丢包率 (L) 的函数:
# 并行 TCP 连接
考虑一段速率为 R 且支持 9 个在线客户 - 服务器应用的链路,每个应用使用一条 TCP 连接,如果一个新的应用加入进来
- 如果新的应用也使用一条 TCP 连接,则每个应用得到差不多相同的传输速率\frac{R}
- 如果新的应用使用了 11 个并行的 TCP 连接,那这个应用就会不公平的分到超过 的带宽