CN 2025 D6
首先,新年快乐,所以我又小摆两天。
今天把传输层这一章整理完毕,然后开始复习操作系统,考完以后再看最后一章。
至于网络安全……考虑到不会考很多,我就不做笔记了,自己做做题得了。
传输层
基于网络层提供的服务,向分布式应用程序提供通信服务。
端到端通信原则
传输层应提供进程之间本地通信的抽象:即运行在不同终端上的应用进程仿佛是直接连在一起的
传输层的有所为、有所不为:
传输层可以通过差错恢复、重排序等手段提供可靠、按序的交付服务;但传输层无法提供延迟保证、带宽保证等服务
传输层通过UDP协议和TCP协议,向应用层提供两种不同的传输服务
1.套接字编程
网络应用传统体系结构:C/S(客户只与服务器通信,客户之间不通信)
进程标识包括:
- 主机地址
- 主机上与该进程关联的端口号
socket API(C/S)
应用需显式地创建、使用和释放套接字
两种传输服务: 1. 不可靠的数据报服务:由UDP协议实现。2. 可靠的字节流服务:由TCP协议实现。
- SOCKET 原语创建一个新的 endpoint,并在传输实体中为其分配 table spaces。
- 调用时指定要使用的 addressing format(寻址格式)、所需的服务类型(例如,可靠的字节流)以及协议。
- 返回文件描述符(就像文件的OPEN调用一样)
- BIND 原语分配网络地址。
- 一旦服务器将地址绑定到套接字,远程客户端就可以连接到它。
- LISTEN 原语为 incoming calls 分配 queue 空间,以防多个客户端同时尝试连接
- Socket 模型的 LISTEN 不是一个阻塞调用
- ACCEPT 原语阻塞并等待传入的连接
- 当请求连接的段到达时,传输实体创建一个与原始套接字具有相同属性的新套接字,并返回其文件描述符。
- 服务器可以fork出一个进程或线程来处理新套接字上的连接,并返回到原始套接字上等待下一个连接。

传输层复用和分用
具体点说,是发送端复用,接收端分用。
复用:发送方传输层将套接字标识置于报文段中,交给网络层
分用:接收方传输层根据报文段中的套接字标识,将报文段交付到正确的套接字
端口号:
熟知端口:0~1023,由公共域协议使用;注册端口:1024~49151,需要向IANA注册才能使用;动态和/或私有端口:49152~65535,一般程序使用
报文段中有两个字段携带端口号
源端口号:与发送进程关联的本地端口号;目的端口号:与接收进程关联的本地端口号
分配方式:客户端常用自动分配;服务器使用指定端口号创建套接字。
UDP分用
UDP套接字使用**<IP地址, 端口号>**二元组进行标识;
接收方传输层收到一个UDP报文段后,会检查报文段中的目的端口号,将UDP报文段交付到具有该端口号的套接字;而源IP地址和端口号会被接收端用来发响应报文。
TCP套接字
监听套接字:服务器平时在监听套接字上等待客户的连接请求,该套接字具有众所周知的端口号
连接套接字:服务器在收到客户的连接请求后,创建一个连接套接字,使用临时分配的端口号
每个连接套接字只与一个客户通信,连接套接字需要使用<源IP地址,目的IP地址,源端口号,目的端口号>四元组进行标识,服务器使用该四元组将TCP报文段交付到正确的连接套接字。
3.UDP详情
UDP提供的服务:进程到进程之间的报文交付;报文完整性检查(Optional):检测丢弃出错的报文
UDP需要实现的功能:1. 复用和分用 2. 报文检错

UDP报文:
- 报头:携带协议处理需要的信息
- 载荷(payload):携带上层数据
source/dest port : 用于复用和分用
length和checksum:用于检错
checksum详情
发送方将报文段看成是由16比特整数组成的序列;对这些整数序列计算校验和;将校验和放到UDP报文段的checksum字段。
接收方对收到的报文段进行相同的计算;与报文段中的checksum字段进行比较。若不相等,说明报文段有错误;相等则认为报文段没有错误

计算UDP校验和时,要包括伪头、UDP头和数据三个部分
伪头:
包括源IP地址,目的IP地址、UDP的协议号、UDP报文段总长度。
目的:为了避免由于IP地址错误等造成的误投递
前面说过,UDP校验和的使用是可选的,若不计算校验和,该字段填入0

UDP适合哪些应用?
- 容忍丢包但对延迟敏感的应用
- 以单次请求/响应为主的应用
- 若应用要求基于UDP进行可靠传输
UDP的优点:
- 应用可以尽可能快地发送报文(不限制发送速率且无建立连接延迟)
- 报头开销小
- 协议处理简单
TCP详情
TCP服务模型:在一对通信的进程之间提供一条理想的字节流管道
点到点,全双工,可靠、有序字节流
需要的机制:建立连接、可靠数据传输、流量控制

重要的TCP选项:
最大段长度(MSS):TCP段中可以携带的最大数据字节数;建立连接时,每个主机可声明自己能够接受的MSS,缺省为536字节
窗口比例因子(window scale):建立连接时,双方可以协商一个窗口比例因子。实际接收窗口大小= window size * 2^window scale
选择确认(SACK):最初的TCP协议只使用累积确认;改进的TCP协议引入选择确认,允许接收端指出缺失的数据字节
发送序号:数据载荷中第一个字节在字节流中的序号
确认序号:期望接收的下一个字节的序号

数据传输:
TCP 在不可靠的IP服务上建立可靠的数据传输
基本机制:
- 发送端:流水线式发送数据、等待确认、超时重传
- 接收端:进行差错检测,采用累积确认机制
高度简化的TCP协议:仅考虑可靠传输机制,且数据仅在一个方向上传输
发送方:
发送策略:流水线式发送报文段
定时器的使用:仅对最早未确认的报文段使用一个重传定时器(与GBN类似)
重发策略:仅在超时后重发最早未确认的报文段(与SR类似,因为接收端缓存了失序的报文段)
接收方:
确认方式:采用累积确认,仅在正确、按序收到报文段后,更新确认序号;其余情况,重复前一次的确认序号(与GBN类似)
失序报文段处理:缓存失序的报文段(与SR类似 )
发送方要处理的事件:
- 收到应用数据:
- 创建并发送TCP报文段
- 若当前没有定时器在运行(没有已发送、未确认的报文段),启动定时器
- 超时:
- 重传包含最小序号的、未确认的报文段
- 重启定时器
- 收到ACK:
- 如果确认序号大于基序号(已发送未确认的最小序号):推进发送窗口(更新基序号)
- 如果发送窗口中还有未确认的报文段,启动定时器,否则终止定时器

TCP通过采用以下机制减少了不必要的重传:
- 只使用一个定时器,避免了超时设置过小时重发大量报文段
- 利用流水式发送和累积确认,可以避免重发某些丢失了ACK的报文段
设置合理的超时值
因为RTT是变化的,所以要估计RTT
平均RTT的估算方法(指数加权移动平均):
*EstimatedRTT= αEstimatedRTT+ (1-α)SampleRTT*
典型地,α= 0. 875(之前估计的RTT占大部分权重)
又因为瞬时RTT和平均RTT有很大的偏差,需要在EstimtedRTT上加一个“安全距离”,作为超时值
估算SampleRTT与EstimatedRTT的偏差(称DevRTT):
D*evRTT= (1-β)DevRTT+ β ** |SampleRTT-EstimatedRTT|
典型地,β= 0.25
设置重传定时器的超时值:TimeoutInterval= EstimatedRTT+ 4 * DevRTT
TCP确认的二义性问题:
- 重传的TCP报文段使用与原报文段相同的序号
- 发送端收到确认后,无法得知是对哪个报文段进行的确认
因此,对重传报文段测量的SampleRTT,可能不准确
解决方法:
- 忽略有二义性的确认,只对一次发送成功的报文段测量SampleRTT,并更新EstimtedRTT
- 当TCP重传一个段时,停止测量SampleRTT
Karn’s Algorithm:解决段超时重传并返回确认后,不清楚确认是回复哪次传输的问题
- 不要更新任何已重传段的估计值
- 每次连续重传时,超时都会加倍,直到段成功传输为止
接收端处理:
- 收到期待的报文段:发送更新的确认序号
- 其它情况:重复当前的确认序号
允许推迟确认:接收端可以在收到若干个报文段后,发送一个累积确认的报文段
TCP协议规定:
- 推迟确认的时间最多为500ms
- 接收方至少每隔一个报文段使用正常方式进行确认

快速重传
发送方可利用重复ACK检测报文段丢失:
- 发送方通常连续发送许多报文段
- 若仅有个别报文段丢失,发送方将收到多个重复序号的ACK
- 多数情况下IP按序交付分组,重复ACK极有可能因丢包产生
TCP协议规定:当发送方收到对同一序号的3次重复确认时,立即重发包含该序号的报文段
所谓快速重传,就是在定时器到期前重发丢失的报文段
TCP可靠传输的设计要点:
- 流水式发送报文段
- 缓存失序的报文段
- 采用累积确认
- 只对最早未确认的报文段使用一个重传定时器
- 超时后只重传包含最小序号的、未确认的报文段
TCP的差错恢复机制可以看成是GBN和SR的混合体:
Crash Recovery
从第N层崩溃中恢复只能由第N+1层完成,(e.g: 传输层可以帮助网络层)并且只有在更高层保留足够的状态信息以重建问题发生之前的状态时才能完成。
TCP流量控制
TCP接收端有一个接收缓存
流量控制:发送端TCP通过调节发送速率,不使接收端缓存溢出
为什么GBN/SR和UDP不需要流量控制
GBN和SR的特点:
- 正确、按序到达的分组被立即交付给上层
- 分组占用的缓冲区被立即释放
发送方可以通过确认序号得知:
- 哪些分组已被移出接收窗口
- 接收窗口还可以接受多少分组
因此,GBN和SR无需额外的流量控制机制。
UDP的特点:
UDP不保证交付,具体表现为:
- 接收端UDP将收到的报文载荷放入接收缓存
- 应用进程每次从接收缓存中读取一个完整的报文载荷
- 当应用进程消费数据不够快时,接收缓存溢出会导致报文数据丢失,UDP对此不负责
因此,UDP协议也不需要流量控制机制。
接收缓存中的可用空间称为接收窗口:RcvWindow= RcvBuffer-[LastByteRcvd-LastByteRead]
接收方将RcvWindow放在报头中,向发送方通告接收缓存的可用空间
发送方限制未确认的字节数不超过接收窗口的大小,即:LastByteSent-LastByteAcked≦ RcvWindow
发送方/接收方对零窗口的处理:
发送方:当接收窗口为0时,发送方必须停止发送
接收方:当接收窗口变为非0时,接收方应通告增大的接收窗口
TCP协议规定:
- 发送方收到“零窗口通告”后,可以发送“零窗口探测”报文段
- 从而接收方可以发送包含接收窗口的响应报文段
糊涂窗口综合症:
当数据的发送速度很快、而消费速度很慢时,零窗口探测的简单实现带来以下问题:
- 接收方不断发送微小窗口通告
- 发送方不断发送很小的数据分组
- 大量带宽被浪费
Sol: 1. 接收方启发式策略
通告零窗口之后,仅当窗口大小显著增加(一半缓存空间或一个MSS)之后才发送更新的窗口通告
当窗口大小不满足以上策略时,推迟发送确认(Max=500ms)
- 发送方启发式策略
发送方应积聚足够多的数据再发送,以防止发送太短的报文段
Nagle算法:
- 只发送第一块,并缓冲其余所有数据,直到第一块被确认。
- 然后在一个TCP段中发送所有缓冲的数据,并再次开始缓冲,直到下一个段被确认。
- 如果足够的数据已经传入以填充一个最大段,则应发送一个新段。
优点:
- 适应网络延时、MSS长度及应用速度的各种组合
- 常规情况下不会降低网络的吞吐量
TCP连接管理
建立一条TCP连接需要确定两件事:
- 双方都同意建立连接(知晓另一方想建立连接)
- 初始化连接参数(序号,MSS等)
(PPT上面讲了一大堆为什么两次握手不可行,反正……就是不可行呗,恕我跳过了)
TCP三次握手建立连接
- 客户TCP发送SYN报文段 (SYN=1, ACK=0)
- 给出客户选择的起始序号
- 不包含数据
- 服务器TCP发送SYNACK报文段 (SYN=ACK=1),服务器端分配缓存和变量
- 给出服务器选择的起始序号
- 确认客户的起始序号
- 不包含数据
- 客户发送ACK报文段 (SYN=0,ACK=1),客户端分配缓存和变量
- 确认服务器的起始序号
- 可能包含数据
选择起始序号:必须避免新、旧连接上的序号产生重叠
TCP在连接内部使用时间戳来扩展32位序列号,使得序列号在最大数据包生存期内不会回绕
在实践中使用伪随机初始序列号进行连接,防止攻击者预测下一个初始序列号,伪造三次握手数据包
TCP连接关闭:Asymmetric release and symmetric release
asymmetric variant:任何一方都可以发出一个 DISCONNECT 原语,发送一个 DISCONNECT 段到远程传输实体。到达后,连接被释放。
symmetric variant:当一方执行 DISCONNECT 后,不再发送更多数据,但仍然接受来自对方的数据。
教材里面提到了一个“两军问题”(Two-Army Problem),还挺有意思
https://blog.csdn.net/stone8761/article/details/51680790
实际解决方法:三次握手 + 计时器到期的时候,无论如何都释放连接
- 引入DISCONNECTION REQUEST(不同于DISCONNECT原语)
结论:传输实体不能很好地自主决定何时断开连接,依赖应用程序

SYN洪泛攻击
攻击者采用伪造的源IP地址,向服务器发送大量的SYN段,却不发送ACK段;导致服务器为维护一个巨大的半连接表耗尽资源,导致无法处理正常客户的连接请求,表现为服务器停止服务。
TCP端口扫描
扫描程序依次与目标机器的各个端口建立TCP连接,根据获得的响应来收集目标机器信息
发送端向目标端口发送SYN报文段:
- 若收到SYNACK段,表明目标端口上有服务在运行
- 若收到RST段,表明目标端口上没有服务在运行
- 若什么也没收到,表明路径上有防火墙,有些防火墙会丢弃来自外网的SYN报文段
网络拥塞:基本理解
PPT上跟交通拥堵做了个类比,二者确实挺像的
流量控制与拥塞控制的异同:
- 流量控制:限制发送速度,使不超过接收端的处理能力
- 拥塞控制:限制发送速度,使不超过网络的处理能力
网络拥塞的后果:进入网络的负载很重,网络吞吐量却很低
拥塞控制常用方法:网络辅助的拥塞控制、端到端拥塞控制(TCP使用)
TCP拥塞控制
发送方根据自己感知的网络拥塞程度,限制其发送速率
发送方利用丢包事件感知拥塞:
拥塞造成丢包和分组延迟增大,而无论是丢包还是分组延迟过大,对于发送端来说都是丢包了
丢包事件包括:重传定时器超时、发送端收到3个重复的ACK。
发送方使用拥塞窗口(cwnd)限制已发送但未确认的数据量:
1 | LastByteSent - LastByteAcked ≤ cwnd |
cwnd会随发送方感知的网络拥塞程度而动态变化。发送速率可表示为:
$$
rate = \frac{cwnd}{RTT} \text{ Bytes/sec}
$$
拥塞窗口的调节策略:AIMD(乘性减,加性增)
发送方检测到丢包后,将cwnd的大小减半(但不能小于一个MSS)。目的:迅速减小发送速率,缓解拥塞
若无丢包,每经过一个RTT,将cwnd增大一个MSS,直到检测到丢包。
slow start(慢启动)
- 拥塞窗口从较小的初始值(如4个段)开始。
- 每收到一个确认(或者说每隔一个RTT),拥塞窗口增加一倍的大小。
- 数据包发送速度逐渐加快,直到拥塞窗口大小超过slow start threshold(慢启动阈值),或者检测到拥塞,或者接收方窗口已满。
- 初始化时,慢启动阈值设为流量控制窗口的大小(也可以任意高)。
- 检测到数据包丢失时,慢启动阈值设置为拥塞窗口的一半,然后拥塞窗口重置为其小初始值,并重新开始慢启动
- 实际上是指数增长,目的是快速探测网络的容量。
区分不同的丢包事件:
收到3个重复的ACK:
- 将cwnd降至一半
- 使用AIMD调节cwnd
超时:
- 设置门限=cwnd/2
- cwnd=1MSS
- 使用慢启动增大cwnd至门限
- 使用AIMD调节cwnd

$$
Average throughout=0.75 W/RTT
$$
TCP的公平性:如果K条TCP连接共享某条带宽为R的瓶颈链路,每条连接应具有平均速度R/K
拥塞控制的发展
- TCP-BIC: Binary Increase Congestion
如发生丢包时窗口大小是W1,为保持满载而不丢包,满载窗口应小于W1; 如检测到丢包并将窗口乘性减小为W2 ,则满载窗口应大于W2.
在ACK时钟的驱动下,将拥塞窗口置为(W1 +W2)/2(新的W2值),不断逼近满载窗口
如窗口再次达到W1而没有丢包,说明满载窗口大于W1 ,则以逼近W1的镜像过程增大拥塞窗口

- TCP CUBIC
- 将BIC算法连续化,用三次函数拟合BIC算法曲线
- 拥塞窗口成为距上次丢包的时间t 的函数,t取值位于两次丢包之间,不再根据RTT间隔来确定调整窗口的时机,避免了RTT不公平问题
- 已实现在Linux 2.6.18中

- Google BBR
- Data Center TCP
- DCCP
传输层协议的发展
MPTCP的优势:多径带宽聚合,提升传输的可靠性,支持链路的平滑切换
QUIC(不考)