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

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

服务端(已上传)

 客户端:

代码:

#include 
#include 
#include 
#include           /* See NOTES */
#include 
#include 
#include 
#include 
#include 

//自定义报错提示
#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));
	}


	//
}

运行结果:

网络编程day03(UDP中的connect函数、tftp)_第1张图片

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

今日思维导图

你可能感兴趣的:(网络,udp,网络协议)