嵌入式学习——3——UDP TFTP简易文件传输

tftp协议概述

简单文件传输协议,适用于在网络上进行文件传输的一套标准协议,使用UDP传输

特点:

        是应用层协议

        基于UDP协议实现

数据传输模式

        octet:二进制模式(常用)

        mail:已经不再支持

TFTP通信过程总结

  1. 服务器在69号端口等待客户端的请求
  2. 服务器若批准此请求,则使用 临时端口 与客户端进行通信。
  3. 每个数据包的编号都有变化(从1开始)
  4. 每个数据包都要得到ACK的确认,如果出现超时,则需要重新发送最后的数据包或ACK包
  5. 数据长度以512Byte传输的,小于512Byte的数据意味着数据传输结束

TFTP协议分析

差错码:

0 未定义,差错错误信息

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.

8 Unsupported option(s) requested.

#include "../header.h"#define S_IP "192.168.125.30"
#define S_PORT 69typedef struct file_header {int size;char *file_report;
} file_header_report;
char buf[516] = "";
char fileName[128] = {0};
int sockfd = -1;
int data_num = 0;void download_file(struct sockaddr_in *addr);
void upload_file(struct sockaddr_in *addr);
void dealerror(short errno);
file_header_report get_report_RW(short type);
file_header_report get_report_ACK(short type, short blknumber);int main(int argc, char const *argv[]) {// 服务器地址 ,初始地址用于链接请求,但是不是用于实际数据交互struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(S_PORT);addr.sin_addr.s_addr = inet_addr(S_IP);char choose = 0;while (1) {printf("**************************\n");printf("******** 1. 下载 *********\n");printf("******** 2. 上传 *********\n");printf("******** 3. 退出 *********\n");printf("**************************\n");printf("请输入>>> ");choose = getchar();while (getchar() != 10) {};switch (choose) {case '1':download_file(&addr);break;case '2':upload_file(&addr);break;case '3':exit(EXIT_SUCCESS);break;default:printf("输入错误!请重新输入\n");}}close(sockfd);return 0;
}
void upload_file(struct sockaddr_in *addr) {if (sockfd == -1) { // 判断一下,防止重复创建套接字sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0) {perror("socket");return;}}// 发送上传请求printf("请输入要上传的文件名:\n");file_header_report file_report = get_report_RW(2);if (access(fileName, F_OK) != 0) {printf("文件不存在\n");return;}data_num = 0;if (sendto(sockfd, file_report.file_report, file_report.size, 0,(struct sockaddr *)addr, sizeof(struct sockaddr)) == -1) {perror("1111sendto 数据包");return;}// recv_addr 用于 实际数据交互的地址struct sockaddr_in recv_addr;socklen_t recv_addr_len = sizeof(recv_addr);int read_size = recvfrom(sockfd, buf, 516, 0, (struct sockaddr *)&recv_addr,&recv_addr_len);short *first_no = (short *)buf;short *blk_num = (short *)(buf + 2);// 处理报错信息 == 5if (ntohs(*first_no) == 5) {dealerror(ntohs(*blk_num));return;}if (ntohs(*first_no) == 4) {int upload_fd = open(fileName, O_RDONLY);if (upload_fd < 0) {perror("open");return;}while (1) {// 发送数据包bzero(buf, sizeof(buf));// 拼接数据包short *p1 = (short *)buf;*p1 = htons(3);short *p2 = (short *)(buf + 2);*p2 = htons(data_num);int file_size = read(upload_fd, buf + 4, 512);if (file_size < 0) {perror("read");exit(1);}if (sendto(sockfd, buf, file_size + 4, 0,(struct sockaddr *)&recv_addr,sizeof(recv_addr)) == -1) {perror("sendto 数据包");exit(1);}bzero(buf, sizeof(buf));int read_size_n =recvfrom(sockfd, buf, 4, 0, (struct sockaddr *)&recv_addr,&recv_addr_len);short *first_noe_n = (short *)buf;short *blk_nume_n = (short *)(buf + 2);// 确认ACK包// 编号是否与本地的标号一致,一致的话就进行下一个编号的数据传送if (ntohs(*first_noe_n) == 4 && ntohs(*blk_nume_n) == data_num) {// 这种情况说明本次上传成功data_num++;} else {printf("上传失败\n");if (ntohs(*first_no) == 5) {dealerror(ntohs(*blk_num));return;}break;}// 如果最后一次读取,就结束循环if (file_size < 512) {printf("上传成功\n");break;}}} else {printf("上传失败\n");}
}
// 下载
void download_file(struct sockaddr_in *addr) {if (sockfd == -1) { // 判断一下,防止重复创建套接字sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0) {perror("socket");return;}}// 发送下载请求printf("请输入要下载的文件名:\n");file_header_report file_report = get_report_RW(1);if (sendto(sockfd, file_report.file_report, file_report.size, 0,(struct sockaddr *)addr, sizeof(struct sockaddr)) == -1) {perror("sendto 数据包");return;}struct sockaddr_in recv_addr;socklen_t recv_addr_len = sizeof(recv_addr);while (1) {// 接收数据包// 数据包返回的服务器端地址需要存在recv_addr,因为服务器处理数据的端口并非原来端口,// 该地址recv_addr 用于后续的ack包 发送给服务器用于确认bzero(buf, sizeof(buf));int read_size = recvfrom(sockfd, buf, 516, 0,(struct sockaddr *)&recv_addr, &recv_addr_len);int download_fd = open(fileName, O_RDWR | O_CREAT | O_APPEND, 0666);if (download_fd < 0) {perror("open");return;}short *first_no = (short *)buf;short *blk_num = (short *)(buf + 2);// 处理报错信息 == 5if (ntohs(*first_no) == 5) {dealerror(ntohs(*blk_num));break;}// 这是数据包 == 3if (ntohs(*first_no) == 3) {if (read_size > 4) {write(download_fd, buf + 4, read_size - 4);}// 发送ACK*first_no = htons(4);char newbuf[4] = {0};short *p1 = (short *)newbuf;*p1 = htons(4);short *p2 = (short *)(newbuf + 2);*p2 = *blk_num;if (sendto(sockfd, newbuf, 4, 0, (struct sockaddr *)&recv_addr,sizeof(recv_addr)) == -1) {perror("sendtoACK\n");}printf("发送ACK成功\n");if (read_size < 516) {printf("下载完成\n");break;}}close(download_fd);}
}
// 处理报错信息
void dealerror(short errno) {int erno = 0;switch (errno) {case 1:printf("File not found");break;case 2:printf("Access violation");break;case 3:printf("Disk full or allocation exceeded");break;case 4:printf("illegal TFTP operation");break;case 5:printf("Unknown transfer lD");break;case 6:printf("File already exists");break;case 7:printf("No such user");break;case 8:printf("Unsupported option(s) requested");break;default:break;}return;
}/*** @description: 组装请求体数据包* @param {short} type  1--- 下载  2---上传* @return {*}*/
file_header_report get_report_RW(short type) {bzero(buf, sizeof(buf));fgets(fileName, sizeof(fileName), stdin);if (strlen(fileName) > 1) {fileName[strlen(fileName) - 1] = '\0';}short *p1 = (short *)buf;*p1 = htons(type);char *p2 = buf + 2;strcpy(p2, fileName);char *p4 = p2 + strlen(p2) + 1;strcpy(p4, "octet");int size = 2 + strlen(p2) + strlen(p4) + 2;file_header_report fh = {size, buf};return fh;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/15318.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Qt学习记录(14)线程

前言&#xff1a; 我的臀部已经翘到可以顶起一屁股债了 为什么要使用线程 什么时候用线程 复杂的数据处理 头文件.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTimer>//定时器头文件QT_BEGIN_NAMESPACE namespace Ui { class Widget; }…

Python+Flask+Pandas怎样实现任意时间范围的对比数据报表

话不多说,有图有源码: 1.上图 2.因为是低代码的,只能发重要有用的代码片段了 实现思路:1)获取指定时间范围内的数据:2)df合并 #----------年份替换----------------for syear in range(int(byear),int(eyear)1):start_datestr(syear)strbdate[4:]end_datestr(syear)stredate…

【大数据】MapReduce JAVA API编程实践及适用场景介绍

目录 1.前言 2.mapreduce编程示例 3.MapReduce适用场景 1.前言 本文是作者大数据系列专栏的其中一篇&#xff0c;前文我们依次聊了大数据的概论、分布式文件系统、分布式数据库、以及计算引擎mapreduce核心概念以及工作原理。 书接上文&#xff0c;本文将会继续聊一下mapr…

光源亮度检测应用笔记

光源亮度检测应用笔记 光电检测应用光电二极管等效模型和基本参数连接并联电阻&#xff08;RJ&#xff09;串联电阻&#xff08;RS&#xff09;结电容&#xff08;CJ&#xff09;暗电流&#xff08;ID&#xff09; 光电二极管电流-电压转换器无源光电二极管电流-电压转换器有源…

C++ Primer 第五版 第十三章 拷贝控制

当定义一个类时&#xff0c;我们显式地或隐式地指定在此类型的对象拷贝、移动、赋值和销毁时做什么。一个类通过定义五种特殊的成员函数来控制这些操作&#xff0c;包括&#xff1a;拷贝构造函数&#xff08;copy constructor&#xff09;、拷贝赋值运算符&#xff08;copy-ass…

柯桥职场人出差必备的商务口语-职场差旅口语提问篇

May I reconfirm my flight? 我可以确认我的班机15857575376吗&#xff1f; Where can I make a reservation? 我到哪里可以预订&#xff1f; Do I have to make a reconfirmation? 我还要再确认吗&#xff1f; Is there any discount for the USA Railpass? 火车通行…

node.js —— 解读http模块

目录 http模块&#xff1a; http模块的引入&#xff1a; 创建web服务器的基本步骤&#xff1a; web服务器的一些基本属性&#xff1a; 上述知识汇总案例&#xff1a; http模块&#xff1a; http模块的引入&#xff1a; const http require (http) 创建web服务器的基本步骤…

探索未来,与移动云共舞

探索未来&#xff0c;与移动云共舞 在数字化飞速发展的今天&#xff0c;云计算已经成为企业、政府乃至个人用户不可或缺的一部分。而在众多云服务提供商中&#xff0c;移动云凭借其独特的优势&#xff0c;为用户带来前所未有的体验。接下来&#xff0c;让我们一起走进移动云的世…

LeetCode题练习与总结:从中序与后序遍历序列构造二叉树--106

一、题目描述 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 示例 1: 输入&#xff1a;inorder [9,3,15,20,7], postorder [9,15,7,20,3] 输出…

等保三级云防火墙正版--免费部署满足要求

正版授权内部部署配置授权免费 1、超时退出 2、病毒防护 3、防火墙策略 4、密码复杂度和登录失败处理 5、特征库 点赞关注 私信获取 获取授权 Q 8-5-0-3-4-7-3-3-5

MCU复位电路

【单片机复位电路&#xff0c;巧妙的RC无处不在。】https://www.bilibili.com/video/BV1XW4y1571r?vd_source3cc3c07b09206097d0d8b0aefdf07958 左侧的RESET引脚正常情况下是低电平&#xff0c;是高电平复位&#xff1b;右侧的RESET引脚正常情况下是高电平&#xff0c;是低电…

【电源专题】什么是局部放电(Partial Discharge)

什么是局部放电? 当电压施加在含有两个以上绝缘材料的绝缘物体时,有一个绝缘材料发生放电且至少仍有一个绝缘材料维持正常的绝缘状态,此放电现象称之为局部放电(Partial Discharge)。 举例来说,当待测物的绝缘材料中存在异常气隙,因为空气的介电系数比绝缘材料低以及空气的…

家政服务,让您的家更温馨

家&#xff0c;是我们生活的港湾&#xff0c;也是我们心灵的归宿。在这个快节奏的时代&#xff0c;每个人都在为了生活而奔波。然而&#xff0c;家务琐事却常常成为我们忙碌生活中的绊脚石。为了解决这个问题&#xff0c;家政行业应运而生&#xff0c;为您的生活带来便利与舒适…

vite搭建React+ts+eslint+prettier

一、vite搭建ts模板 npm create vitelatest 项目名 -- --template react-ts//进入到项目文件夹 npm inpm run dev 初始化完成后已经配置好eslint src下一般只留下 初始化git仓库(可选) git init . 二、配置prettier npm i prettier eslint-config-prettier eslint-plugi…

【论文速读】GPT-1:Improving Language Understanding by Generative Pre-Training

摘要 自然语言理解包括广泛的不同的任务&#xff0c;如文本隐含、问题回答、语义相似性评估和文档分类。虽然大量的未标记文本语料库非常丰富&#xff0c;但用于学习这些特定任务的标记数据非常稀缺&#xff0c;这使得经过区别训练的模型要充分执行任务具有挑战性。我们证明&a…

Ubuntu(22.04)不能上网解决办法

想必大家可能在别的贴子看到用以下指令的方法&#xff0c;但是在22版本的ubuntu是行不通的&#xff0c;问题在于22版本中网络管理器的名字压根不是network-manager&#xff0c;而是 NetworkManager. sudo service network-manager stop sudo rm /var/lib/NetworkManager/Netw…

短剧APP开发,短剧行业发展下的财富密码

今年以来&#xff0c;短剧市场展现出了繁荣发展的态势&#xff0c;成为了一个风口赛道。 短剧具有不拖沓、时长短、剧情紧凑等优势&#xff0c;顺应了当代人的生活&#xff0c;是当代人的“电子榨菜”。 短剧的快速发展同时也带动了新业态新模式的发展&#xff0c;短剧APP就是…

ClickHouse vs. Elasticsearch: 计数聚合的工作原理

本文字数&#xff1a;7875&#xff1b;估计阅读时间&#xff1a;20 分钟 审校&#xff1a;庄晓东&#xff08;魏庄&#xff09; 介绍 在另一篇博客文章中&#xff0c;我们对 ClickHouse 和 Elasticsearch 在大规模数据分析和可观测性用例中的性能进行了比较&#xff0c;特别是对…

python-找出四位数中的玫瑰花数

【问题描述】玫瑰花数指一个n位数&#xff08;n>4),其每位上的数字的n次幂之和等于本身。 请求出所有四位数中的玫瑰花数 【输入形式】 【输出形式】 【样例输入】 【样例输出】1634 8208 9474 【样例说明】 【评分标准】 完整代码如下&#xff1a; for n in ra…

《计算机网络微课堂》1-2:因特网概述

1-2&#xff1a;因特网概述 网络、互连网&#xff08;互联网&#xff09;和因特网因特网发展的三个阶段因特网的标准化工作因特网的组成 ‍ 网络、互连网&#xff08;互联网&#xff09;和因特网 我们首先介绍网络、互联网&#xff08;互连网&#xff09;因特网的基本概念&a…