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

基于UDP的TFTP文件传输

代码:

#include <myhead.h>

//实现下载功能
int download(int cfd,struct sockaddr_in sin)
{
	char buf[516] = "";  //定义资源包
	char fileName[128] = "";  //定义文件名
	printf("请输入文件名:");
	scanf("%s",fileName);  
	getchar();
	
	//打开文件
	int fd = -1;
	if((fd = open(fileName,O_RDWR|O_CREAT|O_TRUNC|0666)) == -1)
	{
		perror("open error");  //读写形式创建文件,文件名为输入的文件名
		return -1;
	}

	//组装请求包
	short *p1 = (short *)buf;
	*p1 = htons(1);
	char *p2 = buf + 2;
	strcpy(p2,fileName);
	char *p3 = p2+strlen(p2)+1;
	strcpy(p3,"octet"); 
	int size = 4+strlen(p2)+strlen(p3);  //整体长度
	
	//先发送下载请求到服务器
	if(sendto(cfd,buf,size,0,(struct sockaddr*)&sin,sizeof(sin))==-1)
	{
		perror("sendto error");
		return -1;
	}
	printf("请求成功!\n");
	socklen_t socklen = sizeof(sin);
	
	char *p5 = buf + 4; //确定数据的位置以及差错信息的位置

	while(1)
	{
		bzero(buf,sizeof(buf));
		int res=recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,&socklen);
		int A = buf[1];  //因为小端存储,操作码放在buf的第二位
		if(A == 3)  //当操作码为3时,证明是数据包,正常接收
		{
			write(fd,p5,sizeof(buf));
			buf[1]=4;   //将操作码改为4,即ACK
			//将buf前四位发送回去,因为操作码已经修改,发回去四位当做ACK回复
			sendto(cfd,buf,4,0,(struct sockaddr*)&sin,sizeof(sin));
		}
		else if(A == 5)  //当操作码为5时,证明为ERROR
		{
			printf("%s\n",p5);
			return -1;
		}
		if(res < 516)  //当接收到的字节数小于516时,证明已经接收完成,关闭循环
			break;
	}
	printf("下载完成\n");
	close(fd);  //关闭文件
}

//实现上传功能
int upload(int cfd,struct sockaddr_in sin)
{
	char buf[516] = "";  //定义资源包
	char fileName[128] = "";  //定义文件名
	printf("请输入文件名:");
	scanf("%s",fileName);  
	getchar();
	
	//打开文件
	int fd = -1;
	if((fd = open(fileName,O_RDONLY)) == -1)
	{
		perror("open error");  //只读形式打开文件,文件名为输入的文件名
		return -1;
	}

	//组装请求包
	short *p1 = (short *)buf;
	*p1 = htons(2);   //操作码为2代表要上传
	char *p2 = buf + 2;
	strcpy(p2,fileName);
	char *p3 = p2+strlen(p2)+1;
	strcpy(p3,"octet"); 
	int size = 4+strlen(p2)+strlen(p3);  //整体长度
	
	//先发送上传请求到服务器
	if(sendto(cfd,buf,size,0,(struct sockaddr*)&sin,sizeof(sin))==-1)
	{
		perror("sendto error");
		return -1;
	}
	printf("请求成功!\n");
	socklen_t socklen = sizeof(sin);
	int n = 1;
	while(1)
	{
		bzero(buf,sizeof(buf));
		recvfrom(cfd,buf,4,0,(struct sockaddr*)&sin,&socklen);
		int res = read(fd,buf+4,sizeof(buf)-4); //将文件的512位写入数据包
		buf[1]=3;   //将操作码改为3,即数据包
		
		//将buf发送,因为操作码已经修改,发回去数据加上了操作码和块编号
		sendto(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,sizeof(sin));
		if(res==0)  //证明已经上传完成,关闭循环
			break;
	}
	printf("上传完成\n");
	close(fd);  //关闭文件

}
int main(int argc, const char *argv[])
{
	if(argc != 2)
	{
		printf("input error");
		return -1;
	}

	//创建套接字
	int cfd = socket(AF_INET,SOCK_DGRAM,0);
	if(cfd == -1)
	{
		perror("socket error");
		return -1;
	}
	//填充服务器结构体
	struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(69);
	sin.sin_addr.s_addr = inet_addr(argv[1]);

	int key = 0;
	while(1)
	{
		system("clear");
		printf("\t\t菜单\t\t\n");
		printf("\t\t1.下载\t\t\n");
		printf("\t\t2.上传\t\t\n");
		printf("\t\t0.关闭\t\t\n");
		printf("请输入选项:");
		scanf("%d",&key);
		getchar();
		switch(key)
		{
			case 1:
				{
					//下载
					int A =download(cfd,sin);

				};break;
			case 2:
				{
					//上传
					int B =upload(cfd,sin);
				};break;
			case 0:
				{
					goto A;
				};break;
			default:
				printf("请输入正确的选项!\n");
		}
		//阻塞
		printf("输入任意键,按回车清空");
		while(getchar() != '\n');
	}
	
A:
	close(cfd);


	return 0;
}

上传文件
在这里插入图片描述
下载文件
在这里插入图片描述


http://www.kler.cn/news/149973.html

相关文章:

  • 关于X86机器上运行GnuCobol的研究
  • 【Pytorch】Visualization of Feature Maps(5)——Deep Dream
  • Java常见的面试题(很基础那种)
  • 【Java】泛型的简单使用
  • Leetcode(面试题 08.01.)三步问题
  • 【开题报告】海洋多源数据质量控制应用服务的WebServer设计与实现
  • 大数据-之LibrA数据库系统告警处理(ALM-37003 GTM主备不同步或者GTM主备断连)
  • C语言——深入理解指针(3)
  • 轻量封装WebGPU渲染系统示例<38>- 动态构建WGSL材质Shader(源码)
  • 【从删库到跑路 | MySQL总结篇】表的增删查改(进阶下)
  • Spine深入学习———— 渲染
  • Buzz库python代码示例
  • 通往AGI的大模型MultiAgent的RL是对的但HF有上限
  • Windows 10和11的一个专用的设置菜单,让清理空间变得方便快捷
  • pkpmbs 建设工程质量监督系统 文件上传漏洞复现
  • QML TextField Button 属性 pyside6
  • 【hacker送书第4期】推荐4本Java必读书籍(各送一本)
  • async和await详解(C#)
  • “2024上海智博会、2024北京智博会”双展联动,3月上海,6月北京
  • Java面向对象第8天
  • LeetCode.24两两交换链表中的节点
  • Redis 入门和环境搭建
  • CentOS 7 部署 Nacos (单机版)
  • 基于springboot实现实习管理系统的设计与实现项目【项目源码+论文说明】
  • SpringBoot项目发送邮件
  • LeetCode无重复字符的最长字符串的Java实现
  • Python武器库开发-前端篇之JavaScript介绍(三十三)
  • linux 内核文件读写
  • oracle常用通用sql脚本——查询前用户的表空间信息
  • 快速操控鼠标行为!Vue鼠标按键修饰符让你事半功倍