TFTP 的基本理论


目录

  1. 通信流程
  2. 数据报文格式
  3. 传输终结
  4. 异常处理
  5. 数据丢失和超时

TFTP(Trivial File Transfer Protocol,简单文件传输协议)是UDP协议族中的一个用来在客户机与服务器之间进行简单文件传输的协议,提供不复杂、开销不大的文件传输服务。端口号为69,基于RFC1350协议。

1 通信流程 / Communication Flow

TFTP协议主要基于UDP进行,传输过程主要如下:

客户端从服务器下载:                       客户端向服务器上传:

Client----RRQ---->Server                          Client----WRQ---->Server

<----DATA----       block = 1                      <----ACK----         block = 0

----ACK---->                                          ----DATA---->       block = 1

……                                                 <----ACK----

……

其中有以下几点注意事项:

  1. Client向Server的69端口发送RRQ或者WRQ;
  2. 每个数据报文都是一个完整的block size,512bytes,发送不完整的数据包代表传输结束,若恰好为整数倍,则还需发送一个0bytes的数据报文
  3. 发送方在一定时间内没收到ACK,则需重新发送数据。

2 数据报文格式 / Data Message Format

主要包括5种数据报文格式,序号即是其opcode:

  1. RRQ        2. WRQ         3. DATA        4. ACK          5. ERROR

2.1 RRQ / WRQ packet

  2 bytes      string    1 byte   string   1 byte

----------------------------------------------------------------

|  Opcode  |  Filename  |  0  |  Mode  |  0  |

----------------------------------------------------------------

其中filename为长度不定的字符串,mode的前后均有一个比特的0作为分隔符,mode为netascii、octet或者mail之一,大小写不敏感

netascii – ascii码传输,需要发送方和接收方自己解码ascii码;

octet – 文件传输,字节模式,较为常用

mail – 邮件传输,基本不用

2.2 DATA packet

      2 bytes     2 bytes   n bytes

--------------------------------------------

|  Opcode  |  Block  |  Data  |

--------------------------------------------

数据报文格式中,Block为数据报文的序号,因为只有2个字节,所以是1-65535。当 data block是512 byte时,能接受的文件大小是512*65536=32MB,不过后面的tftp修订允许data block达到1468 byte(以太网MTU(1500)-TFTP header(4)-UDP header(8)-IP header(20)),那么能够传输的大小是1468*65535=93M。不过如果tftp实现循环利用序列号的话(65535的下一个序号是0),理论上可以传输的文件大小没有限制。

2.3 ACK packet

      2 bytes     2 bytes

------------------------------

|  Opcode  |  Block  |

------------------------------

ACK报文中,Block是应答的数据报序列号,WQR的ACK报文Block序列号为0。所有的报文都有ACK报文作为应答,除了,

  1. 重复的ACK
  2. 结束报文
  3. 报文传送超时

2.4 ERROR packet

    2 bytes      2bytes       string    1 byte

------------------------------------------------------------

|  Opcode  |  ErrorCode  |  ErrMsg  |  0  |

------------------------------------------------------------

错误报文的格式如上所示,Opcode是5,ErrorCode是错误代码,ErrMsg是错误信息,结尾以一个比特的0作为分隔符。

2.5 加解码packet

加解码的方式可按照下面的示例代码完成,其中用到了 struct 模块

 import struct
RRQ = 1
WRQ = 2
DATA = 3
ACK = 4
ERROR = 5 class TFTPReadWriteRequest():
@staticmethod
def encode(op, file_name, mode='octet'):
opcode_select = {'r': RRQ, 'w': WRQ}
opcode = opcode_select[op]
packet = struct.pack('!H%dsb%dsb' % (len(file_name), len(mode)), opcode, file_name.encode(), 0, mode.encode(), 0)
return packet @staticmethod
def decode(msg_bytes):
opcode = struct.unpack('!H', msg_bytes[:2])[0]
fileName = msg_bytes[2:].decode('utf-8').split('\x00')[0]
mode = msg_bytes[2:].decode('utf-8').split('\x00')[1]
print('=== Transfer mode is %s' % mode)
return opcode, fileName class TFTPData():
@staticmethod
def encode(block_number, data):
packet = b'\x00\x03'
packet += struct.pack('!H', block_number)
packet += data
return packet @staticmethod
def decode(data_msg):
opcode = struct.unpack('!HH', data_msg[:4])[0]
block_num = struct.unpack('!HH', data_msg[:4])[1]
data = data_msg[4:]
return opcode, block_num, data class TFTPAck():
@staticmethod
def encode(block_num):
packet = b''
packet += b'\x00\x04'
packet += struct.pack('!H', block_num)
return packet @staticmethod
def decode(msg_bytes):
opcode = struct.unpack('!HH', msg_bytes)[0]
ack_block = struct.unpack('!HH', msg_bytes)[1]
return opcode,ack_block class ErrorOpcode(Exception):
pass

3 传输终结 / Transmission End

传输终结的标志是传输数据小于512bytes,当接收方收到最后一个数据报文时,仍然需要发送ACK应答(对于接收端意义不大,但发送端需进行确认),在发送完ACK应答后,还需要等待一段时间(默认的超时时间),如果还是收到了发送端发送的最后一个数据报文,说明发送端没收到ACK报文,需要再次发送,直到在等待时间里没有收到数据报文,或者超过了默认的最大重发次数

4 异常处理 / Error Handle

当发送过程中出现错误或者请求无法满足,就会发送ERROR报文,ERROR报文是发完就不管的,没有重发机制,需要接收方借助超时机制来检测错误。错误代码如下:

  0 – Not defined, see error message (if any)

  1 – File not found

  2 – Access violation

  3 – Disk full or allocation exceeded

  4 – Illegal TFTP operation

  5 – Unknown transfer ID

  6 – File already exists

  7 – No such user

5 数据丢失和超时 / Data Loss and Time out

TFTP没有提供报文的错误检查机制,即认为所有接收的报文都是正确的,数据丢失和对端主机服务无法访问等错误需要借助超时机制来检测,在每次发送一个报文的时候,需要设置一个计时器,如果在计时器超时的时候还没有收到下一个数据,则重发上次的报文。如果计时器超时次数超过了最大值,则终止程序。当接收到新的报文时,不管报文正确还是重复,都要重置计时器

相关阅读


1. struct 模块

2. TFTP 通信的 Python 实现

参考链接


http://cizixs.com/2015/04/12/write-tftp-with-python-1

http://blog.csdn.net/u014745194/article/details/71479669

http://blog.csdn.net/u014745194

Python的网络编程[2] -> TFTP 协议[0] -> TFTP 的基本理论的更多相关文章

  1. Python的网络编程[3] -> BOOTP 协议[0] -> BOOTP 的基本理论

    BOOTP协议 / BOOTP Protocol 目录 基本理论 BOOTP 与 DHCP 通信流程 数据报文格式 报文加解码实现 1. 基本理论 / Basic Theory BOOTP(Boots ...

  2. Python的网络编程[1] -> FTP 协议[0] -> FTP 的基本理论

    FTP协议 / FTP Protocol FTP全称为File Transfer Protocol(文件传输协议),常用于Internet上控制文件的双向传输,常用的操作有上传和下载.基于TCP/IP ...

  3. Python的网络编程[4] -> DHCP 协议[0] -> DHCP 的基本理论

    DHCP协议 / DHCP Protocol 目录 DHCP 基本理论 DHCP 通信流程 DHCP 完整报文 DHCP 的 Optional 字段 DHCP 的报文类型 1 DHCP 基本理论 DH ...

  4. Python的网络编程[3] -> BOOTP 协议[1] -> BOOTP 的 Python 实现

    BOOTP实现 / BOOTP Implement 目录 BOOTP 的服务器建立过程 BOOTP 的客户端建立过程 Note: 理论部分请参考文末相关阅读链接 1 BOOTP 的服务器建立过程 服务 ...

  5. Python的网络编程[6] -> Modbus 协议 -> Modbus 的基本理论与 Python 实现

    Modbus协议 / Modbus Protocol 目录 Modbus 协议简介 Modbus RTU协议 Modbus TCP协议与 Python 实现 Modbus 功能码 Modbus TCP ...

  6. Python的网络编程[1] -> FTP 协议[2] -> 使用 ftplib 建立 FTP 客户端

    使用 ftplib 建立 FTP 客户端 用于建立FTP Client,与 pyftplib 建立的 Server 进行通信. 快速导航 1. 模块信息 2. 建立 FTP 客户端 1. 模块信息 1 ...

  7. Python的网络编程[4] -> DHCP 协议[1] -> DHCP 的 Python 实现

    DHCP实现 / DHCP Implement 目录 DHCP 服务器建立过程 DHCP 报文加码实现过程 下面介绍建立一个简单的DHCP服务器,主要用于对基本的DHCP请求进行响应,目前只提供一个I ...

  8. Python的网络编程[1] -> FTP 协议[1] -> 使用 pyftplib 建立 FTP 服务器

    使用 pyftplib 建立 FTP 服务器 pyftplib 主要用于建立 FTP Server,与 ftplib 建立的 Client 进行通信. 快速导航 1. 模块信息 2. 建立 FTP 服 ...

  9. python之网络编程

    本地的进程间通信(IPC)有很多种方式,但可以总结为下面4类: 消息传递(管道.FIFO.消息队列) 同步(互斥量.条件变量.读写锁.文件和写记录锁.信号量) 共享内存(匿名的和具名的) 远程过程调用 ...

随机推荐

  1. 自己搭建php服务器(可接受表单提交,并返回页面)

    0.概述 本demo实现以下功能: ①在html页面输入姓名和邮箱,点击提交(这里为get) ②服务器通过解析表单内容,返回对“姓名”和“邮箱”的一个欢迎页面 1.软件准备 ①xampp 作用:提供a ...

  2. 架构师速成7.3-devops为什么很重要 分类: 架构师速成 2015-07-07 17:22 410人阅读 评论(0) 收藏

    evops是一个很高大上的名字,其实说的简单点就是开发和运维本身就是一个团队的,要干就一起把事情干好.谁出了问题,网站都不行.作为一个架构师,必须要devops,而且要知道如何推行devops. 首先 ...

  3. shell文本处理工具总结

    shell文本处理工具总结 为了效率,应该熟练的掌握自动化处理相关的知识和技能,能力就表现在做同样的一件事情,可以做的很好的同时,耗时还很短. 再次总结shell文本处理的相关规则,对提高软件调试效率 ...

  4. c++知识点总结--new的一些用法

    new operator 将对象产生与heap,不但分配内存而且为该对象调用一个constructor   operator new只是分配内存,没有constructor被调用 有个一个特殊版本,称 ...

  5. 系统编程--标准IO

    1.流和FILE对象 对于国际字符集,一个字符可以由一个以上的字节来表示.标准I/O文件流可以用来操作单字节和多字节(宽,wide)字符集.一个流的方向(orientation)决定了字符是以单字节还 ...

  6. shell之基本语法

    转:   read 命令从 stdin 获取输入并赋值给 PERSON 变量,最后在 stdout 上输出: #!/bin/bash # Script follows here: echo " ...

  7. hdu1712 分组背包 ACboy needs your help

    ACboy needs your help Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Ot ...

  8. oracle定时job粗解

    其中一篇随笔我写了oracle的存储过程大概的介绍,存储过程除了自身有in的param,来进行程序调用处理之外,还可以通过定时任务的方式调用来执行. 应用场景: 数据同步:有两个显示菜单,“信息编辑” ...

  9. ThreadPoolExecutor源码解析

    LZ目前正在做一个批量生成报表的系统,需要定时批量生成多张报表,便考虑使用线程池来完成.JDK自带的Executors工具类只提供创建固定线程和可伸展但无上限的两个静态方法,并不能满足LZ想自定制线程 ...

  10. 为什么实际内存使用量已经超过了memory.soft_limit_in_bytes,但是并没有立即触发try_to_free_pages in try_charge

    kswapd发起的回收过程汇总会通过cgroup的excessed树进行回收,但是这个kwap都是啥时候被唤醒呢?为啥不是mem_cgroup_soft_limit_reclaim 发现在内核在在:p ...