文件共享协议 -- 对TFTP进行更改
1. TFTP协议:
TFTP(Trivial File Transfer Protocol)即简单文件传输协议是一种停止等待协议, 基于不可靠的UDP, 所以TFTP自身实现数据的可靠传输. TFTP与引导程序协议BOOTP协同工作, 主要用于引导无盘系统.
TFTP协议与其它的协议之间的关系:
--------------------------------------------------- | Local Medium | Internet | Datagram | TFTP | --------------------------------------------------- Figure 1-1: Order of Headers
TFTP有5种报文格式:
1=RRQ(读请求) 2=WRQ(写请求) 3=DATA(数据) 4=ACK(确认) 5=ERROR(差错) 2 bytes string 1 byte string 1 byte ------------------------------------------------ | Opcode | Filename | 0 | Mode | 0 | ------------------------------------------------ Figure 1-2: RRQ/WRQ packet 2 bytes 2 bytes n bytes ---------------------------------- | Opcode | Block # | Data | ---------------------------------- Figure 1-3: DATA packet 2 bytes 2 bytes --------------------- | Opcode | Block # | --------------------- Figure 1-4: ACK packet 2 bytes 2 bytes string 1 byte ----------------------------------------- | Opcode | ErrorCode | ErrMsg | 0 | ----------------------------------------- Figure 1-5: ERROR packet
对于每一个RRQ或者DATA报文, 发送方将启动超时重传机制, 期待一个ACK确认报文. TFTP服务器进程在69端口监听, 在收到客户端发来的第一个分组(如RRQ)时, TFTP服务器进程使用一个临时端口向客户端发送块编号为0的第一个数据报文, 并在此临时等待客户端的ACK 0应答. 然后发送后续的数据报文. TFTP服务器进程仍然在69端口为其它的客户进行服务.
因为TFTP服务器进程使用新的端口而不是69端口来应答客户请求, 所以客户收到第一个数据报文时, 必须从socket中得到新的端口地址, 并将ACK确认报文发往此端口.
2. 对TFTP的更改:
- TFTP协议限制单一的服务器与客户端之间的交互, 对TFTP的更改将使客户端能同时从多个服务器获取文件, 也就是WEB中的多点下载.
- TFTP协议要求发送方启用超时与重传机制, 对TFTP的更改只要求客户端做这项工作, 而服务器端不需要. 这样可以消除停止等待.
- 增加一些功能.
使用UDP数据报传输协议. 服务器的监听端口必须使用10220. 客户端使用临时端口.
包的大小:
包的最大长度为4096+20字节.报文类型(type):
这里不使用TFTP中的"操作码"这个名称, 而改为"报文类型(type)".
一共8种报文类型:
0=CONN 1=GET 2=PUT 3=DATA 4=ACK 5=ERROR 6=HEAD 7=LIST
代码 | 描述 |
CONN | 请求建立连接. |
GET | 类似于TFTP中的RRQ, 获取文件的一个数据块. |
PUT | 暂不使用. |
DATA | 数据. |
ACK | 确认. 暂不使用. |
ERROR | 差错. |
HEAD | 获取一个文件的文件大小等信息. |
LIST | 列目录. |
报文可以简单地归类为"请求"与"应答"两种:
- 请求: CONN, GET, HEAD, LIST
- 应答: ACK, DATA, ERROR
报文格式:
下面给出具体的报文格式, 请求与应答为一组:
字段 | 占位 | 备注 | |
请求 |
GET 块大小 块编号 文件名长度 文件名 |
2字节 2 4 2 n |
总是为4096 根据"块大小"将文件的数据分块. 字节数 字符串, 必须使用UTF-8编码. |
应答 |
DATA 块大小 块编号 数据长度 数据 |
2 2 4 2 n |
总是为4096 必须与请求中的块编号相同. 文件内容的字节序列. |
请求 |
HEAD 文件名长度 文件名 |
2字节 2 n |
字符串, 必须使用UTF-8编码. |
应答 |
DATA 数据长度 数据 |
2 2 n |
UTF-8编码的字符串. |
请求 |
LIST 目录名长度 目录名 |
2字节 2字节 n |
字符串, 必须使用UTF-8编码. |
应答 |
DATA 块编号 总块数 数据长度 数据 |
2 2 2 2 n |
目录列表的数据大于4096字节后必须分块传输. UTF-8编码的字符串. |
表格忽略了差错应答, 事实上, 每一个请求都可能产生差错应答, 差错报文中包括一个面向机器的差错代码, 以及一条面向用户的UTF-8编码的字符串. 差错报文格式:
2字节 | 2 | n |
ERROR | 差错代码 | 差错信息 |
不同的请求可能产生的差错代码:
请求代码 | 差错代码 | 备注 |
未知 | 4 | 未定义的请求. |
CONN | 0 | 请求被禁止. |
GET | 404 | 文件不存在. |
HEAD | 404 | 文件或目录不存在. |
LIST | 404 | 目录不存在. |
CONN报文的格式:
2字节 | n |
CONN | IP:Port |
IP:Port是IPv4地址与端口号的UTF-8字符串表示, 以冒号(':')分隔, 例如 222.2.26.2:50000.
交互的开始:
- Client C 向 Server S 发送一个CONN 报文, 报文中包含 C 将要与 S 建立连接的 UDP 地址, 一般情况下即为发送CONN报文所使用的UDP地址.
- S 新建立一个UDP socket 并绑定临时端口, 然后向 C 回复一个CONN 报文(使用监听UDP), 里面含有新建立的UDP socket的地址. 若C成功收到S的CONN报文, 两者的UDP将建立成功.
HEAD应答返回的数据的格式:
应答返回的数据字段是一个UTF-8编码的字符串, 格式为:
文件名<制表符>类型<制表符>文件大小
LIST应答返回的数据的格式:
应答返回的"数据"字段是一个UTF-8编码的字符串, 是以换行符('\n')分隔的行的集合. 每一行的格式为:
文件名<制表符>类型<制表符>文件大小
类型为一个ASCII字符, 区分大小写, 取值范围为: d(目录), f(文件). 文件大小的单位为"字节".
备注:
- 无论操作系统的实现如何, 文件名和目录名区分大小写.
- 总是使用UTF-8编码的字符串.
- 总是使用Little-Endian字节序.
3. 扩展:
- 身份验证.
- 传输速度限制.
4. 图表与数据来源:
- Figure 1-1, Figure 1-2, Figure 1-3, Figure 1-4, Figure 1-5, Figure 1-6 来自 RFC 1350.
参考资料:
- W. Richard Stevens, 美国 , "TCP/IP详解 -- 卷1:协议"
- K. Sollins, MIT, July 1992, "THE TFTP PROTOCOL (REVISION 2)" RFC 1350