第五章 传输层
传输层协议概述
传输层的定位
传输层为 应用层 进程之间的通信提供服务
传输层向高层用户屏蔽了下面网络核心的细节(如网络拓扑、所采用的路由选择协议等),使 应用进程 看见的就是好像在两个传输层实体之间有一条端到端的逻辑通信信道
传输层的两个主要协议
用户数据报协议 UDP (User Datagram Protocol)
传输控制协议 TCP (Transmission Control Protocol)
运输协议数据单元
两个对等运输实体在通信时传送的数据单位叫作 运输协议数据单元 TPDU (Transport Protocol Data Unit)
- TCP 传送的数据单位协议是 TCP 报文段 (segment)
- UDP 传送的数据单位协议是 UDP 报文或用户数据报
[!NOTE] UDP 与 TCP 的区别
UDP 传送数据之前不需要先建立连接,收到 UDP 报后,不需要给出任何确认,不提供可靠交付,但是一种最有效的工作方式
TCP 提供可靠的、面向连接的运输服务,开销较多
传输层的端口
协议端口号 (protocol port number),即端口 (port),是通信的抽象终点
端口用一个 16 位端口号进行标志,允许有 65,535 个不同的端口号
端口号只具有本地意义,只是为了标志本计算机应用层中的各进程,不同计算机的相同端口号没有联系,通信还需要 IP 地址
用户数据报协议 UDP
UDP 概述
UDP 只在 IP 的数据报服务之上增加了一些功能:复用和分用,差错检测
[!NOTE] 什么是复用和分用
复用:多个应用程序通过不同的 UDP 端口号共享同一个 IP 地址来进行通信
分用:根据 UDP 用户数据报首部中的目的端口号,将数据报分别传送到对应的端口
分用时,如果接收方 UDP 发现收到的报文中的目的端口号不正确(即不存在对应于该端口号的应用进程),就丢弃该报文,并由 ICMP 发送“端口不可达”差错报文给发送方。
UDP 的主要特点
- 无连接
- 发送数据之前不需要建立连接
- 使用尽最大努力交付,
- 即不保证可靠交付
- 面向报文
- UDP 一次传送和交付一个完整的报文,不会在运输层里进行拆分
- 没有拥塞控制
- 网络出现的拥塞不会使源主机的发送速率降低
- 支持一对一、一对多、多对一、多对多等交互通信
- 首部开销小,只有 8 个字节
总结来说,就是简单方便,但不可靠
[!QUESTION] 什么是面向报文
发送方 UDP 对应用层交下来的报文,既不合并,也不拆分,按照原样发送
接收方 UDP 对 IP 层交上来的 UDP 用户数据报,去除首部后就原封不动地交付上层的应用进程,一次交付一个完整的报文
所以,应用程序必须选择合适大小的报文
若报文太长,IP 层在传送时可能要进行分片;若报文太短,会使 IP 数据报的首部的相对长度太大;两者均会降低 IP 层的效率
UDP 的首部格式
- 源端口:源端口号。在需要对方回信时选用。不需要时可用全 0。
- 目的端口:目的端口号。终点交付报文时必须使用。
- 长度:UDP 用户数据报的长度,其最小值是 8(仅有首部)。
- 检验和:检测 UDP 用户数据报在传输中是否有错。有错就丢弃。
计算 UDP 检验和:略,见 PPT 30 页
传输控制协议 TCP
TCP 是面向连接的传输层协议,在无连接的、不可靠的 IP 网络服务基础之上增加了保证可靠性的一系列措施,提供可靠交付的服务
IP 网络提供的是不可靠的传输,TCP 的是可靠传输
TCP 主要特点
- TCP 是 面向连接 的传输层协议
- 每一条 TCP 连接只能有两个端点 (endpoint)
- 即,每一条 TCP 连接只能是点对点的(一对一)
- TCP 提供 可靠交付 的服务
-
TCP 提供 全双工 通信
- 双方既是发送方也是接收方
-
面向字节流
[!QUESTION] TCP 面向流的概念
TCP 中的“流”(stream) 指的是流入或流出进程的字节序列
应用程序和 TCP 的交互是一次一个数据块,但 TCP 把应用程序交下来的数据看成仅仅是一连串无结构的字节流
TCP 不保证接收方所收到的数据块和发送方应用程序所发出的数据块具有大小对应关系
但接收方应用程序收到的字节流会和发送方应用程序发出的字节流完全一样
TCP 不关心应用进程一次把多长的报文发送到 TCP 缓存
TCP 根据对方给出的窗口值和当前网络拥塞程度来决定一个报文段应包含多少个字节,形成 TCP 报文段
TCP 的连接
TCP 连接的端点:套接字 (socket) 或插口
套接字 socket = (IP 地址 : 端口号) ,例如 (192.169.1.20 : 2028)
每一条 TCP 连接唯一地被通信两端的两个端点(即两个套接字)所确定:
TCP 连接 ::= {socket1, socket2} = {(IP1: port1),(IP2: port2)}
同一个 IP 地址可以有多个不同的 TCP 连接
同一个端口号也可以出现在多个不同的 TCP 连接中
可靠传输的工作原理
停止等待协议
每发送完一个分组就停止发送,等待对方的确认,在收到确认后再发送下一个分组
出现差错
出现差错的情况有两种,B 都不会发送任何信息:
- B 接收 M1 时检测出了差错,就丢弃 M1,却不通知 A 有分组被丢弃
- M1 在传输过程中丢失了,B 根本不知道
解决方法:超时重传,ACK 过久没收到就重发
ACK 丢失和 ACK 迟到
ACK 丢失或迟到都会导致数据报重复发送,接收方只需要丢弃并发送 ACK 即可
ACK 迟到时,发送方还会额外收到重复的 ACK,只需要丢弃即可
信道利用率
停止等待协议优点:简单;缺点:信道利用率太低
停止等待协议要点
- 停止等待:发送方每次只发送一个分组。在收到确认后再发送下一个分组
- 暂存:在发送完一个分组后,发送方必须暂存已发送的分组的副本,以备重发
- 编号:对发送的每个分组和确认都进行编号
- 超时重传
- 超时计时器的重传时间应当比数据在分组传输的平均往返时间更长一些,防止不必要的重传
连续 ARQ 协议
连续 ARQ(Automatic Repeat request,自动重传请求)采用滑动窗口方法
发送方维持一个 发送窗口,位于发送窗口内的分组都可被连续发送出去,而不需要等待对方的确认
发送方每收到一个确认,就把发送窗口向前滑动一个分组的位置
累积确认:接收方对按序到达的最后一个分组发送确认,表示:到这个分组为止的所有分组都已正确收到了
[!NOTE] 累积确认
优点是容易实现,即使确认丢失也不必重传
缺点是不能向发送方反映出接收方已经正确收到的所有分组的信息
连续 ARQ 协议包括两种方式:
- 回退 N(Go-Back-N ARQ)
- 选择性重传(Selective Repeat ARQ)
TCP 报文段的首部格式
TCP 虽然是面向字节流的,但 TCP 传送的数据单元却是报文段
一个 TCP 报文段分为首部和数据两部分
TCP 报文段首部的前 20 个字节是固定的,后面 4n 字节是根据需要而增加的选项
因此 TCP 首部的最小长度是 20 字节,长度是 4n 字节(n 是整数)
前面几个字段
- 源端口和目的端口,各占 2 字节
- 端口是传输层与应用层的服务接口
- 传输层的复用和分用功能通过端口实现
- 序号,占 4 字节
- TCP 连接中传送的数据流中的每一个字节都有一个序号
- 序号字段的值指的是本报文段所发送的数据的 第一个字节的序号
- 确认号,占 4 字节
- 期望收到对方的下一个报文段的数据的第一个字节的序号
- 若确认号 = N,则表明:到序号 N – 1 为止的所有数据都已正确收到
- 数据偏移:占 4 位
- 每个单位代表 4 byte
- 指出 TCP 报文段的数据起始处距离 TCP 报文段的起始处有多远,即首部长度
- 保留,占 6 位,保留为今后使用,但目前应置为 0
控制位
- 紧急 URG
- URG = 1 时,表明紧急指针字段有效,告诉系统此报文段中有紧急数据,应尽快传送 (相当于高优先级的数据)
- 确认 ACK
- 当 ACK = 1 时,确认号字段才有效,当 ACK = 0 时,确认号无效
- 推送 PSH (PUSH)
- 接收方的 TCP 收到 PSH = 1 的报文段后,就尽快交付给接收的应用进程,不会在接收缓存里排队
- 复位 RST (RESET)
- RST = 1 时,表明 TCP 连接中出现严重差错(如主机崩溃或其他原因),必须释放连接,然后再重新建立运输连接
- 同步 SYN (synchronization)
- SYN = 1 表示这是一个 连接请求 或 连接接受 报文
- SYN = 1,ACK = 0 时,表明这是一个 连接请求 报文段
- SYN = 1,ACK = 1 时,表明这是一个 连接接受 报文段
- 终止 FIN (FINish)
- 用来释放一个连接
- FIN = 1 表明此报文段的发送端的数据已发送完毕,并要求释放运输连接
剩下的几个字段
- 窗口,占 2 字节
- 用于接收方告诉发送方,从本报文的确认号算起,我允许你再发送多少字节
- 窗口值经常在动态变化
- 检验和,占 2 字节
- 检验和检验的范围包括首部和数据两部分
- 在计算检验和时,要在 TCP 报文段的前面加上 12 字节的伪首部
- 紧急指针:占 2 字节
- 在 URG = 1 时有效
- 指出本报文段中的紧急数据的字节数(紧急数据结束后就是普通数据)
- 即,指出了紧急数据的末尾在报文段中的位置
- 选项:长度可变,最长为 40 字节,因为首部偏移字段长度有限
- 填充:使整个 TCP 首部长度是 4 字节的整数倍
MSS
最大报文段长度 MSS (Maximum Segment Size) 是 TCP 报文段中的数据字段的最大长度,即 TCP 报文段长度减去 TCP 首部长度
MSS 应尽可能大,提高网络利用率,但太长又会在 IP 层传输时要分片,增大开销
窗口扩大&时间戳
窗口扩大选项:占 3 字节,其中一个字节表示移位值 S,新的窗口值位数从 16 增大到 (16 + S),相当于把窗口值向左移动 S 位
S 许使用的最大值是 14,窗口最大值增大到 2^(16 + 14) – 1 = 2^30 – 1
说可能会用到,但这里不记了,看 PPT 82 页
TCP 可靠传输的实现
以字节为单位的滑动窗口
TCP 使用流水线传输和滑动窗口协议实现高效、可靠的传输
TCP 的滑动窗口是以字节为单位的
发送方 A 和接收方 B 分别维持一个发送窗口和一个接收窗口
A 根据 B 给出的窗口值,构造出自己的发送窗口
[!EXAMPLE]
可用窗口即发送窗口里还没发送的那部分字节
确认号即接收方希望发送方接下来发送的字节序号
缓存与窗口
发送缓存
发送缓存中的字节:
- 准备发送的字节
- 已发送出但尚未收到确认的字节
发送缓存中的字节数 = 发送应用程序最后写入缓存的字节 - 最后被确认的字节
不能发送太快,否则发送缓存会溢出
接收缓存
接收缓存中的字节:
- 已按序到达但尚未被接收应用程序读取的数据
- 未按序到达的数据
若不能及时读取,缓存最终会被填满,使接收窗口减小到零
如果能够及时读取,接收窗口就可以增大,但最大不能超过接收缓存的大小
注意事项
- 发送窗口是根据接收窗口设置的,但在同一时刻,发送窗口并不总是和接收窗口一样大(因为有一定的时间滞后)
- TCP 标准没有规定对不按序到达的数据应如何处理
- TCP 要求接收方必须有累积确认的功能
超时重传时间的选择 Jacobson/Karels 算法
TCP 采用了一种自适应算法,它记录一个报文段发出的时间,以及收到相应确认的时间, 这两个时间之差就是报文段的往返时间 RTT
加权平均往返时间 \(RTT_S\)
加权平均往返时间 RTTS 又称为平滑的往返时间
\(\alpha\) 根据情况设置,小表示 RTT 值更新较慢,大更新较快
超时重传时间 RTO
RTO (Retransmission Time-Out) 应略大于加权平均往返时间 RTTS
RTTD 是 RTT 偏差的加权平均值。
\(\beta\) 是个小于 1 的系数
往返时间 (RTT) 的测量
[!QUESTION]
超时重传后,如何判定收到的 ACK 是对原来的报文段的,还是对重传报文段的
Karn 算法:只要报文段重传了,就不采用其往返时间样本
[!QUESTION]
当报文段的时延突然增大很多时,在原来得出的重传时间内,不会收到确认报文段,于是就重传报文段
但根据 Karn 算法,不考虑重传的报文段的往返时间样本
这样,超时重传时间就无法更新,造成很多不必要的重传
修正的 Karn 算法:报文段每重传一次,就把 RTO 增大一些
当不再发生报文段的重传时,才根据报文段的往返时延更新平均往返时延 RTT 和超时重传时间 RTO 的数值
选择确认 SACK
[!QUESTION]
若收到的报文段无差错,只是中间还缺少一些序号的数据
那么能否设法只传送缺少的数据而不重传已经正确到达接收方的数据
在 TCP 首部中增加 SACK 选项,以便报告收到的不连续的字节块的边界
左边界 = 第一个字节的序号,右边界 = 最后一个字节序号 + 1。
TCP 的流量控制
流量控制 (flow control) :让发送方的发送速率不要太快,使接收方来得及接收
利用滑动窗口实现流量控制
A 向 B 发送数据,MSS = 100 字节
在连接建立时,B 告诉 A:我的接收窗口 rwnd = 400(字节)
[!BUG] 可能发生死锁
A 向 B 发送数据,MSS = 100 字节
在连接建立时,B 告诉 A:我的接收窗口 rwnd = 400(字节)
解决方法:持续计时器 (persistence timer)
只要 TCP 连接的一方收到对方的零窗口通知,就启动该持续计时器
若持续计时器设置的时间到期,就发送一个零窗口探测报文段,对方在确认这个探测报文段时给出当前窗口值
若窗口仍然是 0,收到这个报文段的一方就重新设置持续计时器
若窗口不是 0,则死锁的僵局就可以打破了