3、TFTP 协议详解
TFTP(Trivial File Transfer Protocol,简单文件传输协议)是 PXE 引导过程中最核心的文件传输协议。客户端从 DHCP 服务器获取 IP 地址和引导文件位置后,必须通过 TFTP 下载引导加载程序(如 pxelinux.0、bootx64.efi)及配置文件。本章深入剖析 TFTP 的协议特点、与 FTP 的差异、端口号及传输模式,为后续搭建 TFTP 服务器和调试启动参数打下坚实基础。
3.1 TFTP 协议特点
TFTP 设计之初就定位为“轻量级、无状态、适用于无盘启动和嵌入式环境”。与 FTP 相比,它牺牲了功能丰富性,换取了极低的实现复杂度和资源占用。
| 特性 | 说明 |
|---|---|
| 传输层协议 | 基于 UDP(而非 TCP),端口号固定为 69(服务器监听端口)。 |
| 无状态 | 每个连接独立,服务器不维护会话状态,崩溃后重启不影响已完成的传输。 |
| 简单确认机制 | 使用停等协议(Stop-and-Wait):发送一个数据块后必须等待 ACK 确认,超时则重传。 |
| 固定数据块大小 | 默认每个数据块 512 字节(最后一块可小于 512 字节)。 |
| 无认证/加密 | 不提供用户认证、目录列表、文件删除等操作,仅支持读(RRQ)和写(WRQ)。 |
| 最小实现 | 代码量极小(约 2-3 KB),适合嵌入到 PXE ROM、UEFI 固件或小型引导加载器中。 |
PXE 为什么选择 TFTP? 因为 PXE 客户端运行在网卡固件或 UEFI 环境中,内存和代码空间极其有限,无法加载完整的 TCP/IP 协议栈。TFTP 基于 UDP,实现简单,仅需几十 KB 的代码即可完成文件下载,是网络引导场景下的最优解。
3.2 TFTP 与 FTP 的区别
虽然 TFTP 和 FTP 都用于文件传输,但两者在设计哲学、协议栈、安全性和适用场景上存在本质差异。下表从 8 个关键维度进行对比:
| 对比维度 | TFTP | FTP |
|---|---|---|
| 传输层 | UDP(无连接) | TCP(面向连接) |
| 端口号 | 69(固定) | 21(控制连接)+ 20(数据连接) |
| 会话状态 | 无状态,每个请求独立 | 有状态,维护会话和用户上下文 |
| 认证机制 | 无 | 用户名/密码(明文或加密) |
| 目录操作 | 不支持(仅读写文件) | 支持 ls、cd、mkdir、rm 等 |
| 传输模式 | octet(二进制)、netascii(文本) | ASCII、Binary、EBCDIC 等 |
| 可靠性 | 停等协议 + 超时重传 | TCP 滑动窗口 + 拥塞控制 |
| 适用场景 | 无盘启动、嵌入式、固件升级 | 大文件传输、交互式文件管理 |
关键区别总结: TFTP 是“最小可行传输协议”,适合受限环境下的简单文件下载;FTP 是“企业级文件管理协议”,功能丰富但开销大。在 PXE 引导中,TFTP 是唯一的选择,因为 PXE 客户端无法运行完整的 FTP 客户端。
3.3 端口号 69 与协议流程
TFTP 服务器在 UDP 端口 69 上监听客户端的读请求(RRQ)或写请求(WRQ)。一旦请求被接受,服务器会动态分配一个临时端口(通常为 1024-65535 之间的随机端口)进行后续数据传输,端口 69 仅用于初始连接建立。
防火墙注意事项: 在搭建 PXE 环境时,必须确保防火墙允许 UDP 端口 69 入站。同时,由于 TFTP 数据连接使用临时端口,某些严格防火墙可能需要开启 UDP 端口 1024-65535 的入站规则,或使用 TFTP 代理/中继来规避此问题。
下图展示了 TFTP 读请求(RRQ)的完整交互流程:
协议流程要点:
- RRQ 请求: 客户端向服务器 UDP 69 端口发送读请求,包含文件名和传输模式(octet)。
- 数据发送: 服务器分配临时端口,将文件拆分为 512 字节的数据块(DATA),每个块附带块编号(从 1 开始)。
- ACK 确认: 客户端收到 DATA 后,发送 ACK 确认块编号。服务器收到 ACK 后发送下一个块。
- 传输结束: 当最后一块数据小于 512 字节时,客户端发送 ACK 后传输完成。如果文件大小恰好是 512 的整数倍,服务器会发送一个 0 字节的 DATA 块作为结束标志。
3.4 传输模式:octet 与 netascii
TFTP 定义两种传输模式,PXE 引导场景下必须使用 octet 模式:
| 传输模式 | 说明 | PXE 适用性 |
|---|---|---|
| octet(二进制) | 以原始字节流传输文件,不做任何转换。适用于二进制文件(引导加载程序、内核、镜像)。 | 必须使用。所有 PXE 引导文件(pxelinux.0、vmlinuz、initrd.img)都是二进制文件,任何字节转换都会导致引导失败。 |
| netascii(文本) | 将文件中的换行符转换为网络标准格式(CR+LF),适用于纯文本文件。 | 不推荐。即使传输配置文件(如 pxelinux.cfg/default),也应使用 octet 模式,避免换行符转换导致解析错误。 |
常见错误: 如果 TFTP 服务器或客户端配置为 netascii 模式传输引导文件,二进制文件中的 0x0A(LF)和 0x0D(CR)会被错误转换,导致文件损坏。PXE 客户端启动时会出现“Could not find kernel image”或“Invalid or corrupt kernel image”等错误。务必确认服务器和客户端都使用 octet 模式。
3.5 TFTP 协议报文格式
理解 TFTP 报文结构有助于调试网络抓包和排查传输问题。TFTP 报文头部固定为 2 字节的操作码(Opcode),后续字段因操作类型而异。
| Opcode | 操作类型 | 报文格式 |
|---|---|---|
| 1 | RRQ(读请求) | Opcode(2B) + 文件名(可变) + 0x00 + 模式(可变) + 0x00 |
| 2 | WRQ(写请求) | Opcode(2B) + 文件名(可变) + 0x00 + 模式(可变) + 0x00 |
| 3 | DATA(数据块) | Opcode(2B) + 块编号(2B) + 数据(0-512B) |
| 4 | ACK(确认) | Opcode(2B) + 块编号(2B) |
| 5 | ERROR(错误) | Opcode(2B) + 错误码(2B) + 错误信息(可变) + 0x00 |
以下是一个典型的 RRQ 请求报文抓包示例(使用 tcpdump 或 Wireshark 查看):
# 使用 tcpdump 抓取 TFTP 流量(端口 69)
tcpdump -i eth0 -nn -s0 -X port 69
# 输出示例(RRQ 请求):
# 16:45:32.123456 IP 192.168.1.100.49152 > 192.168.1.10.69: [udp sum ok]
# TFTP, length 28, RRQ "pxelinux.0" octet
# 0x0000: 0001 7078 656c 696e 7578 2e30 006f 6374 ..pxelinux.0.oct
# 0x0010: 6574 00 et.
# 输出示例(DATA 块):
# 16:45:32.124567 IP 192.168.1.10.49153 > 192.168.1.100.49152: [udp sum ok]
# TFTP, length 516, DATA block 1 (512 bytes data)
# 0x0000: 0003 0001 [512 bytes of binary data...]
调试技巧: 使用
tcpdump -i any port 69 -X 可以实时查看 TFTP 请求的文件名和传输模式。如果看到模式字段为 netascii 而非 octet,说明客户端或服务器配置有误,需要立即修正。
3.6 TFTP 在 PXE 引导中的角色
在 PXE 引导流程中,TFTP 承担了“文件下载通道”的关键角色。下图展示了 PXE 客户端从 DHCP 获取信息后,通过 TFTP 下载引导文件的完整链路:
PXE 引导文件下载顺序:
- 客户端通过 DHCP 获取 next-server(TFTP 服务器地址)和 filename(引导文件路径,如
pxelinux.0)。 - 客户端向 TFTP 服务器(端口 69)发送 RRQ 请求,以 octet 模式下载
pxelinux.0。 - pxelinux.0 运行后,通过 TFTP 下载配置文件
pxelinux.cfg/default(或基于 MAC/IP 的个性化配置)。 - 根据配置文件中的
kernel和initrd指令,继续通过 TFTP 下载 Linux 内核和初始 RAM 磁盘。
3.7 常见 TFTP 问题与排查
| 问题现象 | 可能原因 | 排查方法 |
|---|---|---|
| TFTP 超时(Timeout) | 防火墙阻止 UDP 69 端口;服务器未运行;网络不通 | tcpdump -i any port 69 检查是否有请求到达;systemctl status tftp 检查服务状态 |
| 文件未找到(File not found) | 文件名路径错误;文件权限不足;TFTP 根目录配置错误 | 检查 TFTP 服务器根目录(如 /var/lib/tftpboot)下文件是否存在;使用 tftp 客户端手动测试 |
| 传输模式错误 | 客户端或服务器使用 netascii 模式传输二进制文件 | 抓包检查模式字段;确保服务器配置强制使用 octet 模式 |
| 文件大小限制 | 某些 TFTP 服务器默认限制文件大小(如 32 MB) | 检查服务器配置(如 tftp-hpa 的 --blocksize 和 --max-timeout 参数) |
手动测试 TFTP 服务器:
# 安装 tftp 客户端(如果未安装)
sudo apt install tftp-hpa # Debian/Ubuntu
sudo yum install tftp # RHEL/CentOS
# 手动下载文件测试
tftp 192.168.1.10
tftp> mode octet
tftp> get pxelinux.0
tftp> quit
# 如果成功,当前目录下会生成 pxelinux.0 文件