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

9.12 TFTP通信

客户端设计(仅供参考):

下载本质:读取服务器发送的数据包,写入到本地文件
上传本质:读取本地文件内容,发送给服务器。
1、建立菜单选项,上传和下载。
2、上传功能函数:
1、只读打开本地文件
2、发送上传请求数据包
3、接收服务器应答并回复ACK包
3、1如果接收的是ACK确认包,将包修改为数据包填充本地文件内容并发送给服务器
3、2如果是错误包,上传结束,检查网络。
3、下载功能函数
1、发送下载请求包
2、循环接收服务器数据包
2.1判断收到的包如果是数据包并且块编号正确,就写入客户端文件,然后回复ACK确认包
2.2如果包的长度小于512+2+2,说明接收完毕
2.3如果是错误包。输出对应错误信息并停止接收。

TFTP下载模型:

在这里插入图片描述

TFTP上传模型

在这里插入图片描述

TFTP通信过程总结

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

do_upload(上传文件)

void do_upload(int sockfd,struct sockaddr_in sin,const char *filename){char text[1024] = "";int text_len;socklen_t sinlen = sizeof(sin);int fd;int flags = 0;int num = 0;ssize_t bytes;text_len = sprintf(text,"%c%c%s%c%s%c",0,2,filename,0,"octet",0);if(sendto(sockfd,text,text_len,0,(struct sockaddr *)&sin,sinlen)<0){perror("sendto");exit(1);}while(1){if((bytes = recvfrom(sockfd,text,sizeof(text),0,(struct sockaddr *)&sin,&sinlen))<0){perror("recvfrom");exit(1);}printf("接收操作码:%d,块编号:%hd\n",text[1],ntohs(*(short *)(text+2)));if(text[1] == 5){printf("差错码是:%d,差错信息error:%s\n",ntohs(*(short *)(text+2)),text+4);return ;}else if(text[1] == 4){if(flags == 0){if((fd = open(filename,O_RDONLY))<0){perror("open");exit(1);}flags = 1;printf("文件打开成功:%d\n",fd);}int len = read(fd,text+4,512);if (len < 0) { //检查 read 函数的返回值perror("read");exit(1);}//	printf("%s\n",text+4);if(len == 0){break;}text[1] = 3;*(short *)(text+2) = htons(++num);printf("发送操作码:%d,块编号:%hd\n",text[1],ntohs(*(short *)(text+2)));if(sendto(sockfd,text,len+4,0,(struct sockaddr *)&sin,sinlen)<0){perror("sendto");exit(1);}}}
}

do_download(下载文件)

void do_download(int sockfd,struct sockaddr_in sin,const char *filename){char text[1024] = "";int text_len;socklen_t sinlen = sizeof(sin);int fd;int flags = 0;int num = 0;ssize_t bytes;text_len = sprintf(text,"%c%c%s%c%s%c",0,1,filename,0,"octet",0);if(sendto(sockfd,text,text_len,0,(struct sockaddr *)&sin,sinlen)<0){perror("sendto");exit(1);}while(1){if((bytes = recvfrom(sockfd,text,sizeof(text),0,(struct sockaddr *)&sin,&sinlen))<0){perror("recvfrom");exit(1);}printf("操作码:%d,块编号:%hd\n",text[1],ntohs(*(short *)(text+2)));if(text[1] == 5){printf("错误码是:%d,错误信息error:%s\n",ntohs(*(short *)(text+2)),text+4);return;}else if(text[1]==3){if(flags==0){if((fd = open(filename,O_WRONLY|O_CREAT|O_TRUNC,0664))<0){perror("open");exit(1);}flags = 1;}if((num+1 == ntohs(*(short *)(text+2))) && (bytes == 516)){num = ntohs(*(short *)(text+2));if(write(fd,text+4,bytes-4)<0){perror("write");exit(1);}text[1] = 4;if(sendto(sockfd,text,4,0,(struct sockaddr *)&sin,sinlen)<0){perror("sendto");exit(1);}}else if((num+1 == ntohs(*(short *)(text+2)))&&(bytes<516)){if(write(fd,text+4,bytes-4)<0){perror("write");exit(1);}text[1]=4;if(sendto(sockfd,text,4,0,(struct sockaddr *)&sin,sinlen)<0){perror("sendto");exit(1);}printf("文件下载完毕\n");return;}}}close(fd);
}

运行结果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

完整代码

#include <myhead.h>
#define SERPORT 69
#define SERIP "192.168.11.1"void do_download(int sockfd,struct sockaddr_in sin,const char *filename);
void do_upload(int sockfd,struct sockaddr_in sin,const char *filename);int main(int argc, const char *argv[])
{//1.创建用于通信的套接字文件描述符int clienfd = socket(AF_INET, SOCK_DGRAM, 0);if (clienfd == -1) {perror("socket");return -1;}//2.填充服务器的地址信息结构体struct sockaddr_in sin = {.sin_family = AF_INET,.sin_port = htons(SERPORT),.sin_addr.s_addr = inet_addr(SERIP)};//3.菜单栏选择int choice;char filename[100];while (1) { //3.菜单栏printf("请选择操作:\n");printf("1.上传文件\n");printf("2.下载文件\n");printf("3.退出\n");scanf("%d", &choice);bzero(filename, sizeof(filename));if (choice == 1) {printf("请输入要上传的文件名:");scanf("%s", filename);do_upload(clienfd, sin, filename);} else if (choice == 2) {printf("请输入要下载的文件名:");scanf("%s", filename);do_download(clienfd, sin, filename);} else if (choice == 3) {break;} else {printf("无效选项,请重新选择。\n");}}close(clienfd);return 0;
}void do_download(int sockfd,struct sockaddr_in sin,const char *filename){char text[1024] = "";int text_len;socklen_t sinlen = sizeof(sin);int fd;int flags = 0;int num = 0;ssize_t bytes;text_len = sprintf(text,"%c%c%s%c%s%c",0,1,filename,0,"octet",0);if(sendto(sockfd,text,text_len,0,(struct sockaddr *)&sin,sinlen)<0){perror("sendto");exit(1);}while(1){if((bytes = recvfrom(sockfd,text,sizeof(text),0,(struct sockaddr *)&sin,&sinlen))<0){perror("recvfrom");exit(1);}printf("操作码:%d,块编号:%hd\n",text[1],ntohs(*(short *)(text+2)));if(text[1] == 5){printf("错误码是:%d,错误信息error:%s\n",ntohs(*(short *)(text+2)),text+4);return;}else if(text[1]==3){if(flags==0){if((fd = open(filename,O_WRONLY|O_CREAT|O_TRUNC,0664))<0){perror("open");exit(1);}flags = 1;}if((num+1 == ntohs(*(short *)(text+2))) && (bytes == 516)){num = ntohs(*(short *)(text+2));if(write(fd,text+4,bytes-4)<0){perror("write");exit(1);}text[1] = 4;if(sendto(sockfd,text,4,0,(struct sockaddr *)&sin,sinlen)<0){perror("sendto");exit(1);}}else if((num+1 == ntohs(*(short *)(text+2)))&&(bytes<516)){if(write(fd,text+4,bytes-4)<0){perror("write");exit(1);}text[1]=4;if(sendto(sockfd,text,4,0,(struct sockaddr *)&sin,sinlen)<0){perror("sendto");exit(1);}printf("文件下载完毕\n");return;}}}close(fd);
}void do_upload(int sockfd,struct sockaddr_in sin,const char *filename){char text[1024] = "";int text_len;socklen_t sinlen = sizeof(sin);int fd;int flags = 0;int num = 0;ssize_t bytes;text_len = sprintf(text,"%c%c%s%c%s%c",0,2,filename,0,"octet",0);if(sendto(sockfd,text,text_len,0,(struct sockaddr *)&sin,sinlen)<0){perror("sendto");exit(1);}while(1){if((bytes = recvfrom(sockfd,text,sizeof(text),0,(struct sockaddr *)&sin,&sinlen))<0){perror("recvfrom");exit(1);}printf("接收操作码:%d,块编号:%hd\n",text[1],ntohs(*(short *)(text+2)));if(text[1] == 5){printf("差错码是:%d,差错信息error:%s\n",ntohs(*(short *)(text+2)),text+4);return ;}else if(text[1] == 4){if(flags == 0){if((fd = open(filename,O_RDONLY))<0){perror("open");exit(1);}flags = 1;printf("文件打开成功:%d\n",fd);}int len = read(fd,text+4,512);if (len < 0) { //检查 read 函数的返回值perror("read");exit(1);}//	printf("%s\n",text+4);if(len == 0){break;}text[1] = 3;*(short *)(text+2) = htons(++num);printf("发送操作码:%d,块编号:%hd\n",text[1],ntohs(*(short *)(text+2)));if(sendto(sockfd,text,len+4,0,(struct sockaddr *)&sin,sinlen)<0){perror("sendto");exit(1);}}}
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Leetcode面试经典150题-138.随机链表的复制
  • 构建“零工市场小程序”,服务灵活就业“大民生”
  • 2025年最新大数据毕业设计选题-基于Hive分析相关
  • 34.贪心算法1
  • STP 笔记
  • Village Exteriors Kit 中世纪乡村房屋场景模型
  • 【MySQL】MySQL中JDBC编程——MySQL驱动包安装——(超详解)
  • 探索人工智能的未来趋势
  • CI/CD持续集成和持续交付(git工具、gitlab代码仓库、jenkins)
  • 设计模式 桥接模式(Bridge Pattern)
  • Python数据分析工具(一):Requests的用法
  • Unity实战案例全解析 :PVZ 植物脚本分析
  • 经典sql题(六)查找用户每月累积访问次数
  • 【Hot100】LeetCode—84. 柱状图中最大的矩形
  • Rust表达一下中秋祝福,群发问候!
  • 收藏网友的 源程序下载网
  • centos安装java运行环境jdk+tomcat
  • Docker 笔记(2):Dockerfile
  • Hibernate【inverse和cascade属性】知识要点
  • JavaScript学习总结——原型
  • Linux编程学习笔记 | Linux IO学习[1] - 文件IO
  • Linux编程学习笔记 | Linux多线程学习[2] - 线程的同步
  • Linux各目录及每个目录的详细介绍
  • magento2项目上线注意事项
  • Yii源码解读-服务定位器(Service Locator)
  • 不上全站https的网站你们就等着被恶心死吧
  • 从零开始在ubuntu上搭建node开发环境
  • 道格拉斯-普克 抽稀算法 附javascript实现
  • 人脸识别最新开发经验demo
  • 容器服务kubernetes弹性伸缩高级用法
  • 如何胜任知名企业的商业数据分析师?
  • 数据库写操作弃用“SELECT ... FOR UPDATE”解决方案
  • 腾讯优测优分享 | 你是否体验过Android手机插入耳机后仍外放的尴尬?
  • 如何正确理解,内页权重高于首页?
  • 新海诚画集[秒速5センチメートル:樱花抄·春]
  • ​​​【收录 Hello 算法】10.4 哈希优化策略
  • # wps必须要登录激活才能使用吗?
  • (06)Hive——正则表达式
  • (3)医疗图像处理:MRI磁共振成像-快速采集--(杨正汉)
  • (C++)栈的链式存储结构(出栈、入栈、判空、遍历、销毁)(数据结构与算法)
  • (附表设计)不是我吹!超级全面的权限系统设计方案面世了
  • (附源码)springboot家庭装修管理系统 毕业设计 613205
  • (附源码)ssm基于jsp高校选课系统 毕业设计 291627
  • (三)SvelteKit教程:layout 文件
  • (三十)Flask之wtforms库【剖析源码上篇】
  • (十三)Maven插件解析运行机制
  • (顺序)容器的好伴侣 --- 容器适配器
  • (一)Kafka 安全之使用 SASL 进行身份验证 —— JAAS 配置、SASL 配置
  • (转载)在C#用WM_COPYDATA消息来实现两个进程之间传递数据
  • (轉貼) VS2005 快捷键 (初級) (.NET) (Visual Studio)
  • .CSS-hover 的解释
  • .gitignore文件使用
  • .Net Core中的内存缓存实现——Redis及MemoryCache(2个可选)方案的实现
  • .NET Core中如何集成RabbitMQ
  • .Net Remoting(分离服务程序实现) - Part.3