tftp协议的实现

tftp协议是一种简单的文件传输协议,基于udp,使用端口号69.因为传输层协议使用的udp,因此tftp协议为了保证传输的可靠性,使用了一些手段,比如超时重传,数据块号确认。

tftp协议有两种传输模式,分别是二进制文件传输和文本文件传输模式。可以这样理解,除了文本文件都是二进制文件,传输模式的主要区别在于,文本文件由于是ascii码组成,所以可以认为8位数据中的第一位不重要。二进制文件表示8位数据中的所有位都重要。

协议默认数据块大小512,后续协议支持协商块大小。超时重传时间,模型为典型的cs模型,其中客户端主动发起请求下载或者上传文件。收到数据的一方(不管客户端还是服务器)都会对数据表进行确认,给对端发送确认报文。一共有五种报文类型。分别是读请求报文,写请求报文,数据报文,应答报文,错误报文。操作码用来区别这五种报文。客户端的请求主要是读请求与写请求。用于向客户端请求上传或者下载文件。区分的标记是操作码,short型的数字 1与2.需要注意的是,在发送之前,需要对该字段进行大小端转换,可以这么说,凡是数据类型不是char类型的,都需要进行大小端转换,这里的操作码和后面的block号都需要进行大小端转换。数据报文的操作码为3,然后就是数据的块号,用于对数据的计数。然后就是数据部分。对于回应报文也就是ack报文,只有四字节包括操作码4和回应的块号两字节。错误报文用于传输出现差错的时候使用,包括操作码5和错误号,tftp定义了八种类型的错误码。另外对于带有扩展字段的请求报文,是需要回复oack的,oack的操作码是6.针对扩展字段进行回复,主要是通告对方自己对于扩展字段的支持情况。比如块大小协商的结果。

关于一些功能的实现,基础的数据收发使用sendto与recvfrom,tftp服务器要求使用69号端口监听上传下载请求,传送数据的时候重新打开一个随机端口与客户端进行数据的传送。对于数据报文与应答报文的封装可以使用下面结构体

struct packet

{

short opcode;

short block;

unsigned char data【SIZE】;

}

对于数据报文结构体三个成员变量都需要用到,对于应答报文只需要使用前面两个就行,发送的时候记得转换大小端,然后发送应答报文的时候只需要发送四字节大小,发多了会成为畸形包。 对于请求报文和错误报文的封装同样可以使用这个结构体,使用sprintf进行格式打印。

然后就是block号,这里的block号用于对数据块进行计数,发送回应报文也是对这个block号进行答复,block号可以防止收到重复的包也可以在丢包对时候进行重传使用。这个可以参考tcp重传。

超时重传的实现,使用select函数对套接字进行监听,超时之后返回,然后进行重传,重传一定次数之后如果还是没有收到对应的数据报文或者应答报文进行超时退出并关闭该连接。

传输速度是一个很重要的指标,提升传输速度,在文件读写的时候使用缓冲区,可以加快速度,传输的时候进行大块数据传输,tftpd32最大可以支持32768块大小传输,但是win10不行,只能选择16384块大小。但是这个会有一个问题传送超过socket缓冲区大小的数据会导致sendto失败,返回-1,同时文件操作的函数fread也会有缓冲区,我们可以根据需要自行修改缓冲区,setvbuf可以修改fread缓冲区,将默认的缓冲区换成自己定义的缓冲区,setsockopt修改缓冲区。修改之前可以先使用getsockopt查看一下缓冲区的大小。如果要发送的块大小大于了缓冲区的大小就需要来进行修改了。

但是从最后实现的结果来看,16384块大小和32768块大小差距并不大,三十兆大小的文件四秒左右就能完成下载,上传速度则慢一点。所以当块大小超过一定大小之后,速度的瓶颈就不在这了,硬件的速度限制了最终的速度。

整个协议其实并不复杂,主体由文件操作,socket通讯,报文的封装与解封装组成。整个服务器的框架很简单,初始化之后就一直阻塞在recvfrom等待读写请求到来,收到一个请求的时候,开启一个线程去完成文件操作与数据交互,主线程继续阻塞在recvfrom等待着下一个的请求。经过验证,多个客户端是可以同时读一个文件的,因此这一块不需要互斥操作。如果是上传,则先进行一次判断,看一下本地是否已经存在了同名的文件,之后再根据判断的结果进行操作。判断方式很简单,以只读的方式去打开一个文件,打开了就说明已经存在文件了。

那么tftp是怎么知道文件传完没有的呢?很简单,如果是最后一部分文件,那么最后一块的数据块大小是小于传输指定的块大小的。如果文件刚好是块大小的整数倍,咋办呢。那就发一个数据部分为空的报文。这样对方也能知道文件传输是否结束。

通过这次的简单项目呢,还是学会了不少东西的。在编码之前,一定要先规划好,设计好,不要一拿到要求就直接敲代码了。同时代码的规范性与可读性也必须要严格要求自己。养成一个良好的编码习惯。

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值