传输层
5.1 传输层的功能和端口
传输层是通信子网(下三层)和资源子网(上层应用)之间的桥梁,提供**端到端(进程到进程)**的通信服务。
为什么需要传输层? 网络层负责把数据包从一台主机送到另一台主机(主机到主机),但一台主机上可能运行着多个网络应用(浏览器、微信、邮件客户端等)。传输层通过端口号来区分不同的应用进程,确保数据能送到正确的应用程序。
端口号分类
| 类型 | 范围 | 说明 |
|---|---|---|
| 熟知端口 | 0~1023 | 固定分配给重要协议,如HTTP=80,FTP=21,SMTP=25 |
| 登记端口 | 1024~49151 | 需要IANA登记,如MySQL=3306 |
| 动态端口 | 49152~65535 | 客户端临时使用 |
常用熟知端口
| 协议 | 端口号 | 传输层 |
|---|---|---|
| FTP(数据/控制) | 20/21 | TCP |
| SSH | 22 | TCP |
| Telnet | 23 | TCP |
| SMTP | 25 | TCP |
| DNS | 53 | UDP/TCP |
| HTTP | 80 | TCP |
| POP3 | 110 | TCP |
| HTTPS | 443 | TCP |
| DHCP | 67/68 | UDP |
复用和分用
- 复用:发送方多个应用共用同一个传输层协议发送数据
- 分用:接收方传输层根据端口号将数据交给不同的应用进程
传输层的两个重要协议
| 特性 | TCP | UDP |
|---|---|---|
| 连接 | 面向连接 | 无连接 |
| 可靠 | 可靠传输 | 不可靠 |
| 有序 | 有序到达 | 不保证有序 |
| 流量控制 | 有 | 无 |
| 拥塞控制 | 有 | 无 |
| 开销 | 大(首部20B) | 小(首部8B) |
| 应用 | HTTP、FTP、SMTP、SSH | DNS、DHCP、视频通话、直播 |
5.2 UDP协议
UDP特点
- 无连接——发送数据前不需要建立连接,减少了时延
- 不可靠——不保证数据到达,不重传丢包
- 面向报文——应用层交下来的报文,UDP原封不动地加上首部发送,不拆分也不合并
- 首部开销小——只有8字节
- 支持一对一、一对多、多对一、多对多通信
UDP首部格式(8B)
| 源端口(2B) | 目的端口(2B) | UDP长度(2B) | UDP校验和(2B) |
|---|
- 源端口:可选,不需要时填0
- 目的端口:必须填写
- UDP长度:首部+数据的长度(字节)
- UDP校验和:可选(IPv4中可选,IPv6中强制)
UDP校验和计算
- 计算时加上伪首部(12B,包含源IP、目的IP、协议号、UDP长度)
- 伪首部只用于校验,不传输
- 计算方式:将数据和伪首部每16位一组,求和取反
5.3 TCP协议
TCP特点
- 面向连接——传输前先建立连接
- 可靠传输——无差错、不丢失、不重复、按序到达
- 面向字节流——把应用层的数据看成字节流,TCP自己决定如何分段
- 全双工通信——双方可以同时发送和接收
- 流量控制和拥塞控制
TCP首部格式(固定20B)
| 偏移(bit) | 字段 | 长度(bit) | 说明 |
|---|---|---|---|
| 0 | 源端口 | 16 | |
| 16 | 目的端口 | 16 | |
| 32 | 序号 | 32 | 本报文段数据第一个字节的编号 |
| 64 | 确认号 | 32 | 期望收到对方下一个报文段的第一个字节序号 |
| 96 | 数据偏移 | 4 | 首部长度,单位4B,最小值5 |
| 100 | 保留 | 6 | |
| 106 | 标志位 | 6 | URG/ACK/PSH/RST/SYN/FIN |
| 112 | 窗口 | 16 | 接收窗口大小,用于流量控制 |
| 128 | 校验和 | 16 | 含伪首部 |
| 144 | 紧急指针 | 16 | URG=1时有效 |
| 160 | 选项 | 可变 | MSS、窗口缩放、时间戳等 |
TCP标志位(重点!)
| 标志 | 全称 | 含义 |
|---|---|---|
| URG | Urgent | 紧急指针有效 |
| ACK | Acknowledgment | 确认号有效(建立连接后一直为1) |
| PSH | Push | 立即将数据推送给应用层 |
| RST | Reset | 复位连接(连接异常时使用) |
| SYN | Synchronize | 同步序号,建立连接时使用 |
| FIN | Finish | 释放连接 |
序号和确认号(重点!)
- 序号:本报文段中数据第一个字节的编号
- 确认号:期望收到的下一个字节的序号
- 确认号 = 对方最后一个序号 + 对方发送的数据长度
- 如果对方只发了SYN或FIN(不含数据),确认号 = 序号 + 1
5.4 TCP的连接管理——三次握手
为什么是三次握手? 三次握手是为了确保双方的发送能力和接收能力都正常,并同步初始序号。
三次握手过程
客户端 服务器
| |
| ---- SYN=1, seq=x --------> | 第一次:客户端发SYN
| | 客户端进入SYN-SENT状态
| <--- SYN=1, ACK=1, seq=y, | 第二次:服务器发SYN+ACK
| ack=x+1 -------------- | 服务器进入SYN-RCVD状态
| |
| ---- ACK=1, seq=x+1, ---> | 第三次:客户端发ACK
| ack=y+1 | 客户端和服务器都进入ESTABLISHED状态
每一步的状态变化
| 步骤 | 客户端状态 | 服务器状态 |
|---|---|---|
| 初始 | CLOSED | LISTEN |
| 第一次后 | SYN-SENT | LISTEN |
| 第二次后 | SYN-SENT | SYN-RCVD |
| 第三次后 | ESTABLISHED | ESTABLISHED |
典型例题
例1:主机A向主机B建立TCP连接,A的初始序号为1000,B的初始序号为5000。写出三次握手的序号和确认号。
解:
- 第一次:A→B,SYN=1,seq=1000
- 第二次:B→A,SYN=1,ACK=1,seq=5000,ack=1001(收到A的1000,期望下一个是1001)
- 第三次:A→B,ACK=1,seq=1001,ack=5001
5.5 TCP的连接管理——四次挥手
四次挥手过程
客户端 服务器
| |
| ---- FIN=1, seq=u -------> | 第一次:客户端发FIN(不再发送数据)
| | 客户端进入FIN-WAIT-1状态
| <--- ACK=1, seq=v, --- | 第二次:服务器确认
| ack=u+1 | 服务器进入CLOSE-WAIT状态
| | 客户端进入FIN-WAIT-2状态
| <--- FIN=1, ACK=1, seq=w, | 第三次:服务器发FIN(服务器也发完了)
| ack=u+1 | 服务器进入LAST-ACK状态
| |
| ---- ACK=1, seq=u+1, --> | 第四次:客户端确认
| ack=w+1 | 客户端进入TIME-WAIT状态(等待2MSL)
为什么是四次而不是三次? 因为服务器收到FIN后,可能还有数据要发送,所以先发ACK确认,等数据发完再发FIN。两次挥手之间可能有时间间隔。
为什么TIME-WAIT需要等待2MSL?
- 确保服务器的ACK超时重传能被客户端正确处理
- 防止旧的连接数据干扰新连接
💡 记忆技巧:三次握手像打电话——"喂?"(SYN)、"嗯,我在"(SYN+ACK)、"好,说正事"(ACK)。四次挥手像告别——"我先挂了"(FIN)、"好的"(ACK)、"我也挂了"(FIN)、"拜拜"(ACK)。
5.6 TCP可靠传输
TCP通过以下机制实现可靠传输:
序号机制
- 每个字节都有序号
- 首部中的序号是数据第一个字节的序号
确认机制
- 累积确认:TCP只确认已连续收到的最大序号
- 接收方收到乱序的报文段会缓存但不确认(等待缺失的部分到达)
- 通常使用延迟确认(等一段时间,如果有数据要发就捎带确认)
重传机制
- 超时重传:发送方启动计时器,超时未收到ACK就重传
- 快速重传:收到3个相同确认(冗余ACK)就立即重传,不等超时
5.7 TCP流量控制
滑动窗口机制
TCP通过**接收窗口(rwnd)**进行流量控制。接收方在TCP首部的窗口字段中告知对方自己的接收能力,发送方的发送窗口不能超过接收窗口的大小。
- 接收窗口 = 接收缓存大小 - (已收到的数据 - 已读取的数据)
- 发送窗口 = min(拥塞窗口cwnd, 接收窗口rwnd)
零窗口
- 当接收方窗口为0时,发送方停止发送
- 发送方启动持续计时器,到期后发送零窗口探测报文
- 接收方回复窗口大小,如果还是0,发送方重新设置持续计时器
5.8 TCP拥塞控制(重点!)
拥塞控制 vs 流量控制
- 流量控制:防止"快发慢收"(接收方缓存溢出)
- 拥塞控制:防止"发得太快导致网络拥堵"(路由器缓存溢出)
四个算法
TCP拥塞控制包括:慢开始、拥塞避免、快重传、快恢复。
慢开始(Slow Start)
- 初始cwnd = 1 MSS(最大报文段长度)
- 每收到一个ACK,cwnd增加1 MSS
- 指数增长:1 → 2 → 4 → 8 → ...
- 当cwnd ≥ ssthresh(慢开始门限)时,转入拥塞避免
拥塞避免(Congestion Avoidance)
- 每经过一个RTT,cwnd增加1 MSS(而不是每收到一个ACK)
- 线性增长:避免了指数增长导致的过快拥塞
快重传(Fast Retransmit)
- 发送方连续收到3个对同一序号的冗余ACK
- 不等超时,立即重传丢失的报文段
快恢复(Fast Recovery)
- 与快重传配合使用
- 将ssthresh = cwnd / 2
- 将cwnd = ssthresh + 3(有些实现直接设为ssthresh)
- 直接进入拥塞避免阶段
发生超时时
- ssthresh = cwnd / 2(至少为2)
- cwnd = 1
- 重新进入慢开始阶段
典型例题
例2:一个TCP连接,MSS=1KB,初始ssthresh=16KB。请写出从慢开始到拥塞避免的cwnd变化过程(直到cwnd=24KB时出现3个冗余ACK)。
解:
慢开始阶段:
- RTT 1:cwnd = 1,发送1个,收到ACK后 → cwnd = 2
- RTT 2:cwnd = 2,发送2个,收到ACK后 → cwnd = 4
- RTT 3:cwnd = 4 → 8
- RTT 4:cwnd = 8 → 16 (达到ssthresh=16)
- RTT 5:cwnd = 16 → 进入拥塞避免,cwnd = 17
拥塞避免阶段:
- RTT 6:cwnd = 18
- RTT 7:cwnd = 19
- RTT 8:cwnd = 20
- RTT 9:cwnd = 21
- RTT 10:cwnd = 22
- RTT 11:cwnd = 23
- RTT 12:cwnd = 24(此时收到3个冗余ACK)
快重传+快恢复:
- ssthresh = 24/2 = 12
- cwnd = ssthresh + 3 = 15(有些实现设为12)
- 进入拥塞避免阶段
拥塞控制整个过程总结
cwnd
^
| 慢开始 拥塞避免
24 | \ (收到3冗余ACK)
| \
16 | \ \
| \ \
8 | \ \
| \ \
4 | \ \
| \ \
1 | \ \
+-----------------------------------> RTT
1 2 3 4 5 6 7 8 9 10 11 12
| 事件 | 新ssthresh | 新cwnd | 后续阶段 |
|---|---|---|---|
| 超时 | cwnd/2 | 1 | 慢开始 |
| 3个冗余ACK(快重传) | cwnd/2 | ssthresh+3(或ssthresh) | 拥塞避免 |
📌 408考点提示:拥塞控制是必考题型!
- 给初始值,要求写出每个RTT的cwnd变化
- 判断某个时刻处于什么阶段
- 区分超时和冗余ACK时的不同处理
⚠️ 易错点:
- 慢开始每收到一个ACK加1,不是每个RTT加1(增长是指数级的)
- 拥塞避免每RTT加1(线性增长)
- 快恢复不是"从0开始",而是直接从ssthresh开始线性增长
- cwnd和rwnd的最小值决定实际的发送窗口
5.9 TCP定时器
| 定时器 | 用途 | 说明 |
|---|---|---|
| 超时计时器 | 重传超时 | 发送一个报文段就启动,收到ACK后取消 |
| 持续计时器 | 零窗口探测 | 收到零窗口通知后启动,防止死锁 |
| 保活计时器 | 检测死连接 | 长时间无数据交换时,探测对方是否存活 |
| 时间等待计时器 | TIME-WAIT | 四次挥手中等待2MSL |
RTO(重传超时时间)的计算
- RTO基于RTT(往返时间)估算
- 自适应算法:根据当前网络状况动态调整
- 标准方法:RTO = SRTT + 4 × RTTvar
5.10 传输层核心总结
| 知识点 | 关键内容 |
|---|---|
| 端口 | 熟知(0-1023)、登记(1024-49151)、动态(49152-65535) |
| UDP | 无连接、不可靠、8B首部、面向报文 |
| TCP | 面向连接、可靠、20B首部、面向字节流 |
| 三次握手 | SYN→SYN+ACK→ACK,同步序号 |
| 四次挥手 | FIN→ACK→FIN→ACK,2MSL等待 |
| 流量控制 | 滑动窗口、rwnd |
| 拥塞控制 | 慢开始、拥塞避免、快重传、快恢复 |
端口速记表
| 端口 | 协议 |
|---|---|
| 20/21 | FTP |
| 22 | SSH |
| 23 | Telnet |
| 25 | SMTP |
| 53 | DNS |
| 67/68 | DHCP |
| 80 | HTTP |
| 110 | POP3 |
| 443 | HTTPS |
💡 记忆技巧:应用层协议端口号——"FTP是20、21,SSH是22,Telnet是23,SMTP是25,DNS是53,HTTP是80"。可以按数字顺序记:20/21(FTP)→22(SSH)→23(Telnet)→25(SMTP)→53(DNS)→80(HTTP)。
综合例题
例3:一个TCP连接使用慢开始,初始cwnd=1,ssthresh=16,在第4个RTT结束时检测到超时。求: (1)第5个RTT开始时cwnd和ssthresh的值 (2)第6个RTT结束时cwnd的值 (3)第8个RTT结束时cwnd的值
解:
RTT过程:
- RTT1结束:cwnd=2,ssthresh=16
- RTT2结束:cwnd=4,ssthresh=16
- RTT3结束:cwnd=8,ssthresh=16
- RTT4结束:cwnd=16(达到ssthresh),超时!
(1)第5个RTT开始时:
- ssthresh = 16/2 = 8
- cwnd = 1(超时后从1重新开始)
- 进入慢开始
(2)第6个RTT结束时:
- RTT5:cwnd=1→2(慢开始)
- RTT6:cwnd=2→4(慢开始,还没到ssthresh=8)
- 第6个RTT结束时cwnd=4
(3)第8个RTT结束时:
- RTT7:cwnd=4→8(慢开始,cwnd达到ssthresh=8)
- RTT8:cwnd=8→9(拥塞避免,线性增长+1)
- 第8个RTT结束时cwnd=9