文件共享协议 -- 对TFTP进行更改

ideawu
2007-04
TFTP协议的实现和扩展的源代码. 2007-07-04

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的更改:

  1. TFTP协议限制单一的服务器与客户端之间的交互, 对TFTP的更改将使客户端能同时从多个服务器获取文件, 也就是WEB中的多点下载.
  2. TFTP协议要求发送方启用超时与重传机制, 对TFTP的更改只要求客户端做这项工作, 而服务器端不需要. 这样可以消除停止等待.
  3. 增加一些功能.

使用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 列目录.

报文可以简单地归类为"请求"与"应答"两种:

  1. 请求: CONN, GET, HEAD, LIST
  2. 应答: 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.

交互的开始:

  1. Client C 向 Server S 发送一个CONN 报文, 报文中包含 C 将要与 S 建立连接的 UDP 地址, 一般情况下即为发送CONN报文所使用的UDP地址.
  2. S 新建立一个UDP socket 并绑定临时端口, 然后向 C 回复一个CONN 报文(使用监听UDP), 里面含有新建立的UDP socket的地址. 若C成功收到S的CONN报文, 两者的UDP将建立成功.

HEAD应答返回的数据的格式:

应答返回的数据字段是一个UTF-8编码的字符串, 格式为:

	文件名<制表符>类型<制表符>文件大小

LIST应答返回的数据的格式:

应答返回的"数据"字段是一个UTF-8编码的字符串, 是以换行符('\n')分隔的行的集合. 每一行的格式为:

	文件名<制表符>类型<制表符>文件大小

类型为一个ASCII字符, 区分大小写, 取值范围为: d(目录), f(文件). 文件大小的单位为"字节".

备注:

  1. 无论操作系统的实现如何, 文件名和目录名区分大小写.
  2. 总是使用UTF-8编码的字符串.
  3. 总是使用Little-Endian字节序.

3. 扩展:

  1. 身份验证.
  2. 传输速度限制.

4. 图表与数据来源:

  1. Figure 1-1, Figure 1-2, Figure 1-3, Figure 1-4, Figure 1-5, Figure 1-6 来自 RFC 1350.

参考资料:

  1. W. Richard Stevens, 美国 , "TCP/IP详解 -- 卷1:协议"
  2. K. Sollins, MIT, July 1992, "THE TFTP PROTOCOL (REVISION 2)" RFC 1350