基于UDP的TFTP文件传输

代码:

#include 

//实现下载功能
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;
}

上传文件
基于UDP的TFTP文件传输_第1张图片
下载文件
基于UDP的TFTP文件传输_第2张图片

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