TFTP协议(1)TFTP协议介绍(包括:TFTP的五种报文/报文字段扩展/TFTP的流量控制,差错控制/UDP sendto,recvfrom接口)
TFTP协议(2)TFTP源码实现
https://blog.csdn.net/lqy971966/article/details/121819432
FTP协议和TFTP协议的区别
https://blog.csdn.net/lqy971966/article/details/90934673
1. TFTP协议
1.1 TFTP 背景
TFTP(简单文件传输协议)
由于TFTP最初是设计用于系统引导进程,它不提供用户名和口令。
常用于无盘工作站或路由器从别的主机上获取引导配置文件,由于TFTP报文比较小,能够迅速复制这些文件。
1.2 TFTP协议介绍:
<1>TFTP客户机/服务器模式的文件传输协议
<2>TFTP适用于客户端和服务器之间不需要复杂交互的环境
<3>TFTP承载在UDP之上,端口号69
<4>TFTP仅提供简单的文件传输功能(上传、下载)
<5>TFTP协议传输由客户端发起的
1.3 特点:
1、简单
2、占用资源小,由于TFTP报文比较小,能够迅速复制这些文件
3、适合传递小文件
4、适合在局域网进行传递
5、端口号为69
6、基于UDP实现
7. TFTP是一种类似于停止等待协议
TFTP服务器只有收到客户端的确认报文ACK后才会向客户端接着发送新的数据。
8. 服务器向客户端发送数据的过程中,每次都是发送512B的数据,
如果客户进程收到某个DATA报文中数据部分的长度小于512B,说明这是收到的最后一个报文;
如果待发送的数据的总长度正好是512的整数倍,这就意味着最后一个数据报的长度正好为512B,
此时服务器进程会再次发送一个包含0字节数据的DATA报文
(显然,该报文的总长度为4B=2B操作码+2B块号+0B数据);
9. TFTP协议中,用于读文件的连接和用于写文件的连接的建立方式不同
1.4 缺陷:
TFTP分组中并不提供用户名和口令。这是TFTP的一个特性(即"安全漏洞")
1.5 TFTP五种报文(操作码/功能及详解)
TFTP五种报文分别是: RRQ,WRQ,DATA,ACK和ERROR。
操作码/功能及详解:
1 RRQ 读请求,即下载
模式字段包含:netascii 和 octet 两种
2 WRQ 写请求,即上传
3 DATA 数据包,即DATA
4 ACK 确认码,即ACK
5 ERROR 错误
1.5.1 RRQ 读请求/WRQ 写请求
模式字段中,包含两种字符串中的一种,"netascii"表示ASCII文件,"octet"表示二进制文件;
对于RRQ,客户向TFTP服务器发送读请求后,服务器返回一个块编号为1的DATA报文;
对于WRQ,客户向TFTP服务器发送写请求后,服务器返回的是块编号为1的ACK报文。
总之,不管是RRQ还是WRQ,接收DATA数据的一方(读者)发送ACK确认,而发送DATA数据(写者)的只负责发送数据。
1.5.2 DATA 数据包
由客户或服务器使用(由写者发送),用于传送数据块。
所有的块都用数字顺序编码,从1开始。
在所有的DATA报文中,这个块必须准确地等于512B(源码实现可修改),但最后一个块可以小于或等于512B。
当发送的DATA报文中数据部分的长度小于512B后,表示DATA报文发送完毕,所以小于数据部分512B的DATA数据报可以作为文件结束的标志。
特殊的情况是,当文件中的数据正好是512B的整数倍时,那么发送端必须再发送一个具有数据部分为0B的额外的DATA数据块以表示传输的结束。
数据可以采用ASCII码或二进制组来传送。
1.5.3 ACK 确认码
确认号表示它所收到的块号的一个确认
特殊情况是,当客户向服务器发送一个WRQ请求后,服务器返回给客户的是一个块号为0的ACK报文,表示服务器已经准备好了接收来自客户的数据报。
1.5.4 ERROR 错误
ERROR报文既可以有客户发送,也可以由服务器发送,
当一条连接(如读连接或写连接)不能建立或在数据传输中出现问题时使用。
差错码定义了差错的类型,差错信息是一个可变字节,包含原文中的差错数据。
1.5.5 说明:TFTP报文没有差错检验和字段
从上面的报文格式中可以看出,TFTP报文没有差错检验和字段,
所以接收端检验数据是否出现差错的唯一方法是通过分组该TFTP数据报的UDP首部中的检验和字段。
1.6 TFTP数据包格式
1.6.1 TFTP数据包格式
tftp 图
1.6.2 rrq/wrq可以带带扩展选项
如:
/etc/tftp/1.txt/0/octet/0/60000/0
这个属于其扩展选项: 这个开源在模式后面塞了一个请求长度字段,协议属于扩展字段
格式:
optcode filename mode opt1 opt2
---------------------------------------------------------------------------------
1 | test.txt\0 | octet\0 | timeout\05\0 | blksize\01462\0 |
---------------------------------------------------------------------------------
参考:
https://blog.csdn.net/skyflying2012/article/details/34417905
1.7 TFTP传输过程描述
1.服务器使用端口号69被动打开连接;
2.客户主动打开连接,它使用临时端口作为源端口而端口69作为目的端口,向服务器进程发送RRQ报文;
3.服务器主动打开连接,它使用新的临时端口作为源端口,而使用收到的来自客户的临时端口作为目的端口,
向TFTP客户进程发送DATA报文(2B操作码,2B数据块的块号,512B数据);
4.客户收到服务器的报文后,发送4B的ACK(2B的操作码和2B的数据块号)给TFTP服务器,
告诉它之前发送给客户的数据报已经收到;
5.重复步骤3-4,直到所有请求的数据发送完毕。
tftp2 图
1.7.1 TFTP传输过程说明:
1. TFTP是一种类似于停止等待协议
TFTP服务器只有收到客户端的确认报文ACK后才会向客户端接着发送新的数据。
2. 服务器向客户端发送数据的过程中,每次都是发送512B的数据,
(512B的数据:源码实现可修改改,如60k均可,看下一篇代码实现)
如果客户进程收到某个DATA报文中数据部分的长度小于512B,说明这是收到的最后一个报文;
如果待发送的数据的总长度正好是512的整数倍,这就意味着最后一个数据报的长度正好为512B,
此时服务器进程会再次发送一个包含0字节数据的DATA报文
如果大于512则继续循环处理。
(显然,该报文的总长度为4B的报文(2B操作码+2B块号+0B数据);
3. TFTP协议中,用于读文件的连接和用于写文件的连接的建立方式不同:
3.1 建立读连接的时候,客户首先向服务器发送RRQ读报文,服务器收到该报文后,
直接发回给该客户DATA报文,并且包含第一个数据块(块号为1)。
3.2而建立写连接的时候,客户首先先服务器发送WRQ写报文,服务器收到该报文后,
则发回给客户ACK报文,使用的块号为0;
上面两种情况如果遇到请求报文出错时,均会发回ERROR报文作为响应。
1.7.3 tftp数据交互图
tftp3 图
1.8 TFTP的流量控制
TFTP流量控制采用的是停止等待协议。
TFTP使用DATA报文发送数据块,并等待ACK报文的确认。若在超时之前发送端就收到了确认,它就发送下一个块。
这样,实现流量控制的方法是在发送下一个数据块之前,必须要保证收到了上一个数据块的ACK报文。
客户从服务器读文件:当客户打算向服务器读文件时,先发送RRQ报文,若无问题,服务器就直接发送块号为1的DATA报文(即第一个数据块就直接发送过去了)。
客户向服务器写文件(就是存储文件):当客户打算写文件时,先发送WRQ报文,若无问题,服务器就响应块号为0的ACK报文(不是DATA报文,因为此时服务器是数据接收方,只能发送ACK,同时注意第一个ACK的块编号是0,这样就可以通知客户,我同意了你的写请求)。客户在收到该确认后,就是用块号为1发送第一个数据块给服务器。
1.9 TFTP的差错控制
TFTP的差错机制与其他协议不同,它是对称的,
因为TFTP协议在发送端和接收端都使用了计时器。
(可看下一篇源码实现。)
也就是说,客户和服务器两端,一方使用了DATA报文计时器(发送端),另一方使用ACK报文计时器(接收端)。
若发送端丢失了数据报文,在计时器到期时发送端就重传该数据报文;
若接收端丢失了ACK报文,在超时时接收端就重传该ACK报文。
1.9.1 差错控制常用于这四种情况:
差错控制常用于这四种情况:报文受损、报文丢失、确认丢失和报文重复。
报文受损:当数据块出现差错(通过差错检验,得靠UDP首部)时,接收端能够检测出来并丢弃该报文。发送端等待确认,超时后就重传该数据报。
报文丢失:若数据报丢失了,它就用于不能到达接收方,而确认页不会发出。发送端在超时之后,就会重传该数据报。
确认丢失:确认丢失了,则可能发生两种情况:一是接收端的计时器比发送端的计时器先到期,则接收方重传确认;若发送端的计时器先期,则发送端重传该数据。
报文重复:接收端通过块编号可以检测出数据块的丢失。若数据块重复了,接收端就简单地将其丢弃。
1.10 扩展:UDP的 sendto() 和 recvfrom() 接口
1.10.1 UDP介绍
UDP(user datagram protocol)用户数据报协议,属于传输层。
1. UDP是面向非连接的协议,它不与对方建立连接,而是直接把数据报发给对方。
UDP无需建立类如三次握手的连接,使得通信效率很高。
2. 因此UDP适用于一次传输数据量很少、对可靠性要求不高的或对实时性要求高的应用场景。
1.10.2 UDP通信的过程图及说明
UDP通信的过程如图所示:
图
说明:
服务端:
(1)使用函数socket(),生成套接字文件描述符;
(2)通过struct sockaddr_in 结构设置服务器地址和监听端口;
(3)使用bind() 函数绑定监听端口,将套接字文件描述符和地址类型变量(struct sockaddr_in )进行绑定;
(4)接收客户端的数据,使用recvfrom() 函数接收客户端的网络数据;
(5)向客户端发送数据,使用sendto() 函数向服务器主机发送数据;
(6)关闭套接字,使用close() 函数释放资源;
客户端:
(1)使用socket(),生成套接字文件描述符;
(2)通过struct sockaddr_in 结构设置服务器地址和监听端口;
(3)向服务器发送数据,sendto() ;
(4)接收服务器的数据,recvfrom() ;
(5)关闭套接字,close() ;
1.10.3 sendto
int sendto(int s, const void *buf, int len, unsigned int flags,
const struct sockaddr *to, int tolen);
返回值说明:
成功则返回实际传送出去的字符数,失败返回-1,错误原因会存于errno 中。
参数说明:
s: socket描述符;
buf: UDP数据报缓存区(包含待发送数据);
len: UDP数据报的长度;
flags:调用方式标志位(一般设置为0);
to: 指向接收数据的主机地址信息的结构体(sockaddr_in需类型转换);
tolen:to所指结构体的长度;
1.10.4 recvfrom
int recvfrom(int s, void *buf, int len, unsigned int flags,
struct sockaddr *from, int *fromlen);
返回值说明:
成功则返回实际接收到的字符数,失败返回-1,错误原因会存于errno 中。
参数说明:
s: socket描述符;
buf: UDP数据报缓存区(包含所接收的数据);
len: 缓冲区长度。
flags: 调用操作方式(一般设置为0)。
from: 指向发送数据的客户端地址信息的结构体(sockaddr_in需类型转换);
fromlen:指针,指向from结构体长度值。
例子参考下一篇博文:tftp源码实现
参考:
https://www.cnblogs.com/HpeMephisto/p/11312193.html
2. TFTP协议(2)TFTP源码实现
基于github 开源代码实现部分功能
https://github.com/ideawu/tftpx
下面自己写了一个可以正常跑的demo
https://blog.csdn.net/lqy971966/article/details/121819432
参考:
https://blog.csdn.net/qq_26440221/article/details/78337838
https://www.cnblogs.com/qingtianyu2015/p/5851551.html
https://blog.csdn.net/skyflying2012/article/details/34417905