基于UDP的TFTP文件下载与上传

需求:

        创建UDP客户端实现利用TFTP协议从服务器上下载文件与上传文件。

代码实现过程:

       

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <pthread.h>

#define ERR_MSG(msg) do{\
	fprintf(stderr,"line : %d\n",__LINE__);\
	perror("msg");\
}while(0)

#define IP "192.168.8.130" //填本機ubantuIP ifconfig查看
#define PORT 69 			//1024~49151

#define FIL "download.png"

char buf[600] = "";
ssize_t res = 0;
int sfd = 0;
socklen_t addrlen = 0;
short num = 0;
unsigned short numS = 1;

void* funcS(void* arg){
	struct sockaddr_in sein = *((struct sockaddr_in*)arg);
	int fdS = open("upload.c",O_RDONLY);
	if(fdS < 0){
		ERR_MSG(open);
		return NULL;
	}
	while(1){
		
		bzero(buf,sizeof(buf));
		if(recvfrom(sfd,buf,sizeof(buf),0,(struct sockaddr*)&sein,&addrlen) < 0){
			ERR_MSG(recvfrom);
			return NULL;
		}
		bzero(buf,sizeof(buf));
		sprintf(buf,"%c%c",0,3);
		*(short*)(buf+2) = htons(numS);
	//	*(short*)(buf+2) = htons(numS);
		res = read(fdS,buf+4,512);
		printf("numS = %d htons(numS) = %d num = %d res = %ld\n",numS,htons(numS),num,res);
		if(res < 0){
			ERR_MSG(read);
			return NULL;
		}
		//	printf("buf = %s\n",buf+4);
		if(sendto(sfd,buf,res+4,0,(struct sockaddr*)&sein,sizeof(sein)) < 0){
			ERR_MSG(sendto);
			return NULL;
		}
		if(res != 512){
			printf("文件上传完毕\n");
			break;
		}

			numS++;
	}
}

void* funcR(void* arg){
	struct sockaddr_in sein = *((struct sockaddr_in*)arg);
	int flag = 0;
	int fdR = -1;
	unsigned short numC = 0;
	while(1){
		//接受
		if(0 == flag){
			fdR = open(FIL,O_RDWR|O_CREAT|O_TRUNC,0664);
			if(fdR < 0){
				ERR_MSG(open);
				return NULL;
			}	
			flag=1;
		}

		//UDP是无连接不可靠的,数据包可能会重复接收到的通信
		//可以在本地记录每次收到的包的编号
		//如果本地记录的包的编号与数据包发送回来的块编号不一致,则不处理

		//if(htons(numC+1) == *(unsigned short*)(buf+2)){
			bzero(buf,sizeof(buf));
			res = recvfrom(sfd,buf,sizeof(buf),0,(struct sockaddr*)&sein,&addrlen);
			short *p1 = (short*)(buf+2);
			num = ntohs(*p1);
			printf("num = %d res = %ld\n",num,res);
			if(res < 0){
				ERR_MSG(recv);
				return NULL;
			}

			if(write(fdR,buf+4,res-4) < 0){
				ERR_MSG(write);
				return NULL;
			}

			bzero(buf,sizeof(buf));
			short *p2 = (short*)buf;
			*p2 = htons(4);
			short *p3 = p2+1;
			*p3 = htons(num);
			if(sendto(sfd,buf,4,0,(struct sockaddr*)&sein,sizeof(sein)) < 0){
				ERR_MSG(sendto);
				return NULL;
			}

			if(res!=516){
				fprintf(stderr,"文件下载完毕\n");
				close(fdR);
				break;
			}
			numC++;
		//}
	}
}

int main(int argc, const char *argv[])
{
	//創建报式套接字
	sfd = socket(AF_INET,SOCK_DGRAM,0);
	if(sfd < 0){
		ERR_MSG(socket);
		return -1;
	}

	//填充地址信息結構體
	//根據地址族的不同,地址信息結構體不一致,AF_INET:man 7 ip
	struct sockaddr_in sein;
	sein.sin_family 		= AF_INET; 		//必須填AF_INET
	sein.sin_port 		= htons(PORT); 	//端口號的網絡字節序,1024~49151
	sein.sin_addr.s_addr = inet_addr(IP); 	//本機IP地址的網絡字節序,ifconfig
	addrlen = sizeof(sein);

	char choose = 0;
	int size = 0;
	pthread_t tidS,tidR;
	while(1){
		printf("-------------------------\n");
		printf("---------1.download------\n");
		printf("---------2.upload--------\n");
		printf("---------3.exit----------\n");
		printf("-------------------------\n");
		printf("请输入>>>");
		choose = getchar();
		getchar();
		switch(choose){
		case '1':
			//do_download
			//发送下载请求	
			bzero(buf,sizeof(buf));
			size = sprintf(buf,"%c%c%s%c%s%c",0,1,"5.png",0,"octet",0);
			printf("buf = %s size = %d \n",buf+1,size);
			if(sendto(sfd,buf,size,0,(struct sockaddr*)&sein,sizeof(sein)) < 0){
				ERR_MSG(send);
				return 0;
			}
			printf("send success\n");
			if( pthread_create(&tidR,NULL,funcR,&sein) != 0){
				ERR_MSG(pthread_create);
				return -1;
			}
			pthread_join(tidR,NULL);
			break;

		case '2':
			//do_upload
			发送上传请求
			bzero(buf,sizeof(buf));
			size = sprintf(buf,"%c%c%s%c%s%c",0,2,"upload.c",0,"octet",0);
			if(sendto(sfd,buf,size,0,(struct sockaddr*)&sein,sizeof(sein)) < 0){
				ERR_MSG(send);
				return 0;
			}
			printf("send success\n");

			if( pthread_create(&tidS,NULL,funcS,&sein) != 0){
				ERR_MSG(pthread_create);
				return -1;
			}
			pthread_join(tidS,NULL);
			break;

		case '3':
			printf("程序退出\n");
			return 0;
		}
	}


	close(sfd);
	
	return 0;
}

代码实现结果:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值