TFTP-Experiment
TFTP(简单文件传输协议)是一种基于UDP的简易文件传输协议,主要可用于在局域网内快速传输文件,常用于网络设备引导、系统无盘工作站启动、固件升级等等场景。本实验编写了一个简单的TFTP客户端,可以与Tftpd64服务器进行连接,实现简单的文件上传、下载及日志记录功能,并能丢包重传,具有一定的抗干扰稳定性,附上源代码框架和测试环境
TFTP协议基本特征
- 协议端口:默认使用UDP 69端口
- 传输模式: 无连接,基于UDP协议
- 数据传输单位:每个数据包最大512字节(可扩展,RFC-2348)
- 可靠性:通过确认(ACK)与重传机制来保证数据可靠性
TFTP协议工作流程
客户端请求
客户端向服务器端69号端口发送读请求(RRQ)或写请求(WRQ),相关请求报文格式如下所示:
1 | 2 bytes string 1 byte string 1 byte |
- Opcode字段:指定操作类型 0x0001 = RRQ,0x0002 = WRQ
- Filename字段:指定读取或传输的文件名,
文件名必须以"\0"(字节0x00)结尾,如”test.txt\0” - Mode字段:指定文件传输格式,netascii = 文本模式,octet = 二进制模式,其必须以
"\0"结尾
服务器端响应
如果收到客户端RRQ请求,服务器会发送第一个数据包(DATA包),如果是WRQ请求,服务器会发送第一个确认包(ACK包),表示已做好接收数据准备
文件传输
传输的文件被分成多个DATA包,每个DATA包负载均为512字节(最后一块可能小于512字节),接收端需要持续发送ACK包确认报文,且如果出现超时,需要重传,DATA包与ACK包结构如下所示:
1 | -- DATA包 |
结束会话
当接收方收到的数据包小于512字节时,发送最后一个ACK包并关闭会话即可(因此即使文件大小可以被512整除,也需要发送一个负载为0字节的报文)
TFTP协议特点
丢包重传
通过丢包重传机制,TFTP协议依托不可靠的UDP传输协议,实现较可靠的文件传输功能
TFTP使用停等协议实现丢包重传(Stop-and-Wait ARQ):
- 发送方每次仅发送一个DATA包,只有接收到ACK包才发送下一个指定DATA包
- 接收方每接收到一个DATA包,就发送携带最后一个正确包Block编号的ACK确认报文。若收到的DATA包为重复包或错误Block号包,则丢弃(
TFTP协议为严格顺序传输协议)
TFTP超时重传规则: - 超时时间:典型实现为5s,可根据实际网络通信状况修改
- 重传次数:一个报文最多重新传输次数,超过该值则认为文件传输失败,立刻终止会话
- 发送DATA包后没收到任何ACK确认包
发送方会再次发送同一个Block号DATA包 - 发送RRQ\WRQ\ACK后没收到任何回应
发送方会重复发送同一个请求报文
ERROR报文
一个不常用的TFTP报文,其格式为:
1 | 2 bytes 2 bytes string 1 byte |
- Opcode:固定为5
- ErrorCode:2字节,错误码
- ErrMsg:错误信息字符串,自定义,文本格式可读,以”\0”结尾
常见的错误码有
| ErrorCode | 含义 |
|---|---|
| 0 | 未定义错误(Not defined) |
| 1 | 文件未找到(File not found) |
| 2 | 访问违规(Access violation) |
| 3 | 磁盘满/分配超出(Disk full) |
| 4 | 非法操作(Illegal TFTP operation) |
| 5 | 未知传输 ID(Unknown transfer ID) |
| 6 | 文件已存在(File already exists) |
| 7 | 无效用户(No such user) |
Windows套接字编程
编写简易TFTP程序需要用到Windows套接字编程相关函数,现将函数原型和作用列出:
- WSAStartup函数
WSAStartup函数用于初始化 Windows 套接字库(Winsock),在使用任何套接字相关函数前必须调用。成功返回 0,失败返回错误码
1 | int WSAStartup( |
- WSACleanup函数
WSACleanup函数用于释放 Winsock 库资源,通常在网络操作结束后调用。成功返回 0,失败返回错误码
1 | int WSACleanup(void); |
- sendto函数
sendto函数用于通过指定的套接字向目标地址发送数据,适用于 UDP(无连接)通信,返回值为实际发送的字节数,若失败则返回 SOCKET_ERROR
1 | int sendto( |
- recvfrom函数
recvfrom函数是 UDP 通信中常用的函数,用于接收数据报文,同时获取发送方的地址信息。它适用于无连接的套接字,其成功时,返回接收到的字节数;
失败时,返回 SOCKET_ERROR,可以通过 WSAGetLastError() 获取错误码
1 | int recvfrom( |
轻量级TFTP客户端测试
Upload测试
客户端命令如下:
1 | .\tftp_client.exe -u 127.0.0.1 test.txt netascii |
客户端效果:
Tftp64服务器效果:
Download测试
客户端命令如下:
1 | .\tftp_client.exe -d 10.12.172.220 EUPL-EN.pdf octet |
Tftp64服务器效果:
查看日志,结果如下所示
补:还可以使用测试环境中提供的clumsy-bandwidth工具模拟真实网络通信环境下,进行TFTP丢包率测试。测试结果表明客户端Tftp丢包重传机制可以正常运行
