网络编程day03(UDP中的connect函数、tftp)

news/2024/5/18 13:17:15 标签: 网络, udp, 网络协议

今日任务:tftp的文件上传下载(服务端已经准备好)

服务端(已上传)

 客户端:

代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <strings.h>
#include <fcntl.h>

//自定义报错提示
#define ERR_MSG(msg) do{\
	fprintf(stderr,"__%d__",__LINE__);\
	perror(msg);\
}while(0)

//#define SER_PORT 69
//#define SER_IP "192.168.125.74"
#define SER_PORT 69
#define SER_IP "192.168.125.225"
int do_upload(int cfd,struct sockaddr_in addr);
int do_download(int cfd,struct sockaddr_in addr);
int main(int argc, const char *argv[])
{
	//1.创建socket套接字
	int cfd=socket(AF_INET,SOCK_DGRAM,0);
	if(cfd<0){
		ERR_MSG("socket");
		return -1;
	}
	puts("socket success");


	//3.接受和发送消息
	//目标地址信息
	struct sockaddr_in addr;
	addr.sin_family=AF_INET;
	addr.sin_port=htons(SER_PORT);
	addr.sin_addr.s_addr=inet_addr(SER_IP);
	socklen_t addrlen=sizeof(addr);

	//记录接受信息的目标地址信息
	struct sockaddr_in recv_addr;
	socklen_t recv_addrlen=sizeof(recv_addr);

	while(1){
		puts("---------------------------------");
		puts("------------1.上传---------------");
		puts("------------2.下载---------------");
		puts("------------3.退出---------------");
		puts("---------------------------------");
		puts("请选择>>");
		char choice;
		choice=getchar();
		while(getchar()!='\n');//循环吸收垃圾字符
		switch(choice){
		case '1':
			do_upload(cfd,addr);
			break;
		case '2':
			puts("download");
			do_download(cfd,addr);
			break;
		case '3':
			goto END;
		}
	}
END:

	/*
	   char buf[128];
	   while(1){

	   printf("请输入>>>");
	   fgets(buf,sizeof(buf),stdin);
	   buf[strlen(buf)-1]='\0';



	   int send_res=sendto(cfd,buf,sizeof(buf),0,(struct sockaddr*)&addr,addrlen);
	   if(send_res<0){
	   ERR_MSG("sendto");
	   return -1;
	   }
	   puts("sendto success");
	   if(strcmp(buf,"quit")==0)
	   break;

	   bzero(buf,sizeof(buf));
	   int recv_res=recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&recv_addr,&recv_addrlen);
	   if(recv_res<0){
	   ERR_MSG("recvfrom");
	   return -1;
	   }
	   puts("recvfrom success");
	   printf("[%s:%d]:%s\n",inet_ntoa(recv_addr.sin_addr),ntohs(recv_addr.sin_port),buf);	

	   }

*/
	//4.关闭
	close(cfd);
	return 0;
}
int do_upload(int cfd,struct sockaddr_in addr){
	printf("请输入要上传的文件名.>>>");
	char name[20]="";
	scanf("%s",name);
	while(getchar()!=10);

	//组下载协议
	char buf[516]="";
	//操作码
	unsigned short *p1=(unsigned short*)buf;
	*p1=htons(2);
	//文件名
	char *p2=buf+2;
	strcpy(p2,name);
	//0
	//模式
	char *p4=p2+strlen(name)+1;
	strcpy(p4,"octet");
	//0
	int size=2+strlen(name)+1+strlen(p4)+1;
	//printf("buf==%s;size==%d",buf,size);
	//发送协议给服务器
	if(sendto(cfd,buf,size,0,(struct sockaddr*)&addr,sizeof(addr))<0){
		ERR_MSG("sendto");
		return -1;
	}
	puts("send upload protocal success");
	//打开一个文件,输入
	int fd=open(name,O_RDONLY);
	if(open<0){
		ERR_MSG("open");
		return -1;
	}
	unsigned short bNum=1;
	//重新定义一个地址的结构体,接受服务端传来的临时地址
	struct sockaddr_in dest_addr;
	socklen_t addrlen=sizeof(dest_addr);
	if(recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&dest_addr,&addrlen)<0){
		ERR_MSG("recvfrom");
		return -1;
	}

	while(1){
		//组包:操作码+块编号+数据
		bzero(buf,sizeof(buf));
		unsigned short *opNum=(unsigned short*)buf;
		*opNum=htons(3);
		unsigned short *blockNum=opNum+1;
		*blockNum=htons(bNum);
		char* msg=buf+4;
		int read_res=read(fd,msg,512);
		if(read<0){
			ERR_MSG("read");
		}
		//发包
		ssize_t sendto_res=sendto(cfd,buf,sizeof(buf),0,(struct sockaddr*)&dest_addr,addrlen);
		if(sendto_res<0){
			ERR_MSG("sendto");
			return -1;
		}
		printf("sendto_res=%ld\n----",sendto_res);

		//接受ack
		if(recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&dest_addr,&addrlen)<0){
			ERR_MSG("recvfrom");
			return -1;
		}
		
		opNum=(unsigned short*)buf;
		blockNum=opNum+1;
		if(ntohs(*opNum)==5){
			puts("操作码错误");
			printf("%d %d:%s",ntohs(*opNum),ntohs(*blockNum),msg);
		}else if(ntohs(*opNum)==4){
			if(ntohs(*blockNum)==bNum){
				puts("ACK correct");
			}else{
				puts("ACK incorrect");
				return -1;
			}
		}
		bNum++;

		if(read_res<512){
			printf("bNUm==%d\n",bNum);
			puts("upload done");
			break;
		}
	
	}
	close(fd);

}
int do_download(int cfd,struct sockaddr_in addr){
	printf("请输入要下载的文件名.>>>");
	char name[20]="";
	scanf("%s",name);
	while(getchar()!=10);

	//组下载协议
	char buf[516]="";
	//操作码
	unsigned short *p1=(unsigned short*)buf;
	*p1=htons(1);
	//文件名
	char *p2=buf+2;
	strcpy(p2,name);
	//0
	//模式
	char *p4=p2+strlen(name)+1;
	strcpy(p4,"octet");
	//0
	int size=2+strlen(name)+1+strlen(p4)+1;
	//printf("buf==%s;size==%d",buf,size);
	//发送协议给服务器
	if(sendto(cfd,buf,size,0,(struct sockaddr*)&addr,sizeof(addr))<0){
		ERR_MSG("sendto");
		return -1;
	}
	puts("send download protocal success");
	//新建打开一个文件,等下写入
	int fd=open(name,O_WRONLY|O_CREAT|O_TRUNC,0664);
	if(fd<0){
		ERR_MSG("open");
		return -1;
	}
	//重新定义一个地址的结构体,接受服务端传来的临时地址
	struct sockaddr_in dest_addr;
	socklen_t addrlen=sizeof(dest_addr);
	while(1){
		//接受数据包
		int recv_res=recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&dest_addr,&addrlen);
		if(recv_res<0){
			ERR_MSG("recvfrom");
			return -1;
		}
		unsigned short* opNum=(unsigned short*)buf;
		unsigned short* blockNum=opNum+1;
		char * msg=(char *)(blockNum+1);
		if(ntohs(*opNum)==5){
			puts("操作码错误");
			printf("%d %d:%s",ntohs(*opNum),ntohs(*blockNum),msg);
		}else if(ntohs(*opNum)==3){
			int wr_res=write(fd,msg,recv_res-4);
			if(wr_res<0){
				ERR_MSG("write");
			}else if(wr_res<512){
				puts("recvfrom done");
				break;
			}
		}

		//组ACK包,吾把buf当做ack来使
		*opNum=htons(4);

		//回复ACK包
		sendto(cfd,buf,4,0,(struct sockaddr*)&dest_addr,addrlen);
		bzero(buf,sizeof(buf));
	}


	//
}

运行结果:

不知道是网络的问题还是代码的问题,上传很慢,代码很快正常运行结束了,但是tftp服务端下载到win上很慢,7kb的也要5s以上

今日思维导图


http://www.niftyadmin.cn/n/5038433.html

相关文章

进阶指针(一)

✨博客主页&#xff1a;小钱编程成长记 &#x1f388;博客专栏&#xff1a;进阶C语言 进阶指针&#xff08;一&#xff09; 0.回顾初阶指针1.字符指针1.1 相关面试题 2.数组指针3.指针数组3.1 数组指针的定义3.2 &数组名VS数组名3.3 数组指针的使用 4.数组传参和指针传参4.…

操作系统读书笔记- 01 x86系统架构概览.md-html

x86系统架构概览 真看不懂了… 今天就写这些吧 2.0.处理器工作模式 一般来讲,x86-64处理器具有5种工作模式: 实模式(Real-address Mode):处理器以16位8086的方式工作,只能以简单的段地址:偏移地址方式进行寻址,地址空间只有20位,不具有内存保护、虚拟内存、特权级限制…

抖音seo账号矩阵源码系统

1. 开通多个抖音账号&#xff0c;并将它们归纳为一个账号矩阵系统。 2. 建立一个统一的账号管理平台&#xff0c;以便对这些账号进行集中管理&#xff0c;包括账号信息、内容发布、社区交互等。 3. 招募专业的运营团队&#xff0c;对每个账号进行精细化运营&#xff0c;包括内…

QT连接Sqlite

使用QTCreator&#xff1b; 根据资料&#xff0c;Qt自带SQLite数据库&#xff0c;不需要再单独安装&#xff0c;默认情况下&#xff0c;使用SQLite版本3&#xff0c;驱动程序为***QSQLITE***&#xff1b; 首先创建项目&#xff1b;在 Build system 中应选中qmake&#xff0c;…

北斗导航 | RTD、RTK完好性之B值、VPL与HPL计算(附B值计算matlab源代码)

===================================================== github:https://github.com/MichaelBeechan CSDN:https://blog.csdn.net/u011344545 ===================================================== 1、S矩阵获取 为第i颗卫星测距标准差:

八、逻辑覆盖

不要让你的弱点妨碍你的优势。 有两种互补的逻辑测试方法。 第一种被称为语义逻辑覆盖&#xff0c;这种覆盖只考虑逻辑表达式的含义而不管表达式的构成。语义逻辑覆盖的优点在于即使谓词被写成一种表面不同但是具有等价语义的形式&#xff0c;依然可以产生相同的测试用例。 第二…

PDF文件上传转成base64编码并支持预览

在工作中&#xff0c;有个需求&#xff0c;前端上传PDF文件&#xff0c;需要转成base64编码&#xff0c;传给后端。查看的时候&#xff0c;后端返回base64编码&#xff0c;前端实现PDF预览。 具体实现代码如下&#xff1a; <template><div><!-- 选择文件 --&g…

【计算机网络】 拥塞控制

文章目录 背景TCP的四种拥塞控制算法慢开始与拥塞避免&#xff1a;快重传&#xff1a;快恢复&#xff1a; 流量控制和拥塞控制本质上的 区别 背景 网络中的链路容量和交换节点中的缓存和处理机都有着工作的极限&#xff0c;当网络的需求超过他们的工作极限时&#xff0c;就出现…