当前位置: 首页 > news >正文

Linux网络编程 深入解析TFTP协议:基于UDP的文件传输实战

知识点1【TFTP的概述】

学习通信的基本:通信协议(具体发送上面样的报文)、通信流程(按照什么步骤发送)

1、TFTP的概述

tftp:简单文件传输协议,**基于UDP,**不进行用户有效性验证

基于UDP:编程架构是UDP的

必须创建UDP套接字

套接字分类:UDP套接字,TCP套接字,原始套接字

数据传输格式(模式选择):

octet:二进制模式

netascii:文本模式

2、TFTP的通信过程

决定了 编程流程

我们主要写客户端

注意:

服务器中,在69号端口后,是临时端口,临时端口是只要socket,不bind。因此需要创建一个新的线程,线程中执行socket()

TFTP通信过程总结

3、TFTP协议分析

读写请求是用户自己发送的,我们现在不考虑选项部分。

数据包516个字节,当小于516个字节的时候,表示下载 结束(最后一个报文),块编号中存储的是该数据包的编号。这里注意一定要对操作码进行判断,是3才可以确认是数据包。

收到数据包 我们需要回复一个ACK,ACK中的块编号需要和数据包的ACK相同

这里有一个技巧,客户端直接把收到的内容的前4个字节发送给服务器,只需要修改操作码的第二个字节即可

错误码操作码是5,差错码是不同的错误有不同的编号,差错信息说明错误。

OACK是比如我们设置了选项部分,需要设置的,相对复杂,我们下面介绍。

想一想

传输的数据的大小一定是 512Byte 吗?

由于网络的原因,一方收不到另一方的数据怎么办?

1、不一定需要512,选项修改

2、这里服务器发送数据包后,如果没有收到ACK,它会等待,并从发送数据包处开始计时,超出 超时时间后,才会发出错误码,提示重发。

而这里的数据包长度修改,超时时间的修改,都需要借助选项来完成

4、TFTP带选项的读写报文

选项和值成对出现。

OACK是在修改了选项后,服务器向客户端发送的一个报文,是起一个确认作用的。

我们结合上图,客户端一旦修改了选项部分,客户端不再是立即发送数据,而是发送OACK,让客户端确认是否要这样修改(通过ACK,块编号中:0表示同意,这也是为什么数据编号是从1开始的),客户端给予回应后,服务器才会执行发送数据的操作。

选项的种类

tsize 选项

当读操作时,tsize 选项的参数必须为“0”,服务器会返回待读取的文件的大小

当写操作时,tsize 选项参数应为待写入文件的大小,服务器会回显该选项

blksize 选项

修改传输文件时使用的数据块的大小(范围:8~65464)

timeout 选项

修改默认的数据传输超时时间(单位:秒)

注意:

1、选项没有顺序

2、在使用tsize 读操作的时候,tsize的默认参数是0(因为读时不知道文件的大小),收到OACK的时候,会返回实际文件的大小(nB说明是字符串需要转换)

总结

1、可以通过发送带选项的读/写请求发送给 server 2、如果 server 允许修改选项则发送选项修改确认包 3、server 发送的数据、选项修改确认包都是临时 port 4、server 通过 timeout 来对丢失数据包的重新发送

知识点2【TFTP案例】

需求:编写TFTP客户端(不带选项),从客户端下载文件

流程:

1、创建UDP套接字

2、构建读请求报文,并发送到服务器69号端口

3、while 循环接收,buf是516个字节,recvform的返回值是获取到数据的长度

这里需要创建一个文件描述符取接收

4、关闭文件描述符 和 套接字

构建 读写请求报文 的方式

使用sprintf组包,当sendto时,有一个内容长度,使用sprintf的返回值:组包的总长度,目的端口写69

代码演示

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main(int argc, char const *argv[])
{if(argc != 3){printf("error\\n");printf("modo:./a.out 196.168.9.28 a.txt\\n");_exit(-1);}//创建套接字,目的:向服务器发送数据int fd_sock = socket(AF_INET,SOCK_DGRAM,0);if(fd_sock < 0){perror("socket");return 0;}//sprintf组包,返回值使用len_sprintf接收。格式: 0 1 文件名 0 模式 0 char arr_sprintf[64] = "";int len_sprintf = sprintf(arr_sprintf,"%c%c%s%c%s%c",0,1,argv[2],0,"octet",0);//发送sprintf组包(读写报文)struct sockaddr_in addr_rw;memset(&addr_rw,0,sizeof(addr_rw));addr_rw.sin_family = AF_INET;addr_rw.sin_port = htons(69);addr_rw.sin_addr.s_addr = inet_addr(argv[1]);sendto(fd_sock,arr_sprintf,len_sprintf,0,(struct sockaddr *)&addr_rw,sizeof(addr_rw));/*  接收服务器发出的 数据报文,报文的前四个字节:操作码(2),端口码(2),数据(512),存储在arr_recv中数据段操作码判断,下面是3的操作重复性判断,定义一个unsigned short num = 0,num+1与端口码比较数据写入文件,并将端口码赋值给numACK 回应服务器 arr_recv前四个字节进行处理即可*///操作码为5操作//关闭套接字 及 文件描述符 //输出错误原因unsigned short num = 0;int fd_w = open(argv[2],O_WRONLY | O_CREAT,0664);if(fd_w < 0){close(fd_sock);perror("open");return 0;}int len = 0;unsigned char arr_recv[516] = "";struct sockaddr_in addr_recv;int len_recv = sizeof(addr_recv);do{len = recvfrom(fd_sock,arr_recv,sizeof(arr_recv),0,(struct sockaddr *)&addr_recv,&len_recv);if(arr_recv[1] == 3){if((unsigned short)(num + 1) == ntohs(*(unsigned short *)(arr_recv +2))){write(fd_w,arr_recv + 4,len - 4);//ack应答num = ntohs(*(unsigned short *)(arr_recv +2));printf("%d\\n",num);}arr_recv[1] = 4;sendto(fd_sock,arr_recv,4,0,(struct sockaddr *)&addr_recv,sizeof(addr_recv));}else if(arr_recv[1] == 5){close(fd_sock);close(fd_w);unlink(argv[2]);printf("%s\\n",arr_recv+4);_exit(-1);}} while (len == 516);//关闭文件描述符,套接字,关闭文件close(fd_w);close(fd_sock);return 0;
}

代码运行结果

结束

代码重在练习!

代码重在练习!

代码重在练习!

今天的分享就到此结束了,希望对你有所帮助,如果你喜欢我的分享,请点赞收藏夹关注,谢谢大家!!!

相关文章:

  • 三大等待和三大切换
  • PP-OCR的安卓端部署
  • Google Colab测试部署Qwen大模型,实现PDF转MD场景OCR 识别(支持单机环境)
  • CSS3笔记
  • 设计模式 --- 外观模式
  • 基于FPGA的AES加解密系统verilog实现,包含testbench和开发板硬件测试
  • 【ESP32-IDF笔记】06-触摸传感IO配置
  • 基于尚硅谷FreeRTOS视频笔记——6—滴答时钟—上下文切换
  • OpenAI重返巅峰:o3与o4-mini引领AI推理新时代
  • Qt QThread 两种线程管理方法
  • 【 解决Cline插件无法激活及DeepSeek模型请求卡顿或者无法加载问题】
  • C++ `unique_ptr` 多线程使用
  • SpringAI+DeepSeek大模型应用开发——5 ChatPDF
  • 深入解析C++驱动开发实战:优化高效稳定的驱动应用
  • Spring_MVC 快速入门指南
  • 汽车免拆诊断案例 | 2011款雪铁龙世嘉车刮水器偶尔自动工作
  • wordpress 垂直越权(CVE=2021-21389)漏洞复现详细教程
  • 初识Redis · C++客户端string
  • 先导木工机床与养老领域的探索之旅
  • 仿腾讯会议项目实现——设置配置文件
  • 南部战区位南海海域进行例行巡航
  • 东风着陆场近日气象条件满足神舟十九号安全返回要求
  • 中行一季度净赚超543亿降2.9%,利息净收入降逾4%
  • 五一假期上海地铁部分线路将延时运营,这些调整请查收
  • 辽宁辽阳市白塔区一饭店发生火灾,事故已造成22人遇难3人受伤
  • 跟着京剧电影游运河,京杭大运河沿线六城举行京剧电影展映