网络编程 day4

 tftp协议上传下载

 

#include
#define SERIP "192.168.125.32"
#define SERPORT 69

//定义下载函数/*********************************************/
int do_download(int cfd,struct sockaddr_in sin)
{
	//获取文件文件名
	char filename[40] = "";;
	printf("请输入需要下载的文件名:\n");
	scanf("%s",filename);
	getchar();
	//以只写的形式打开文件
	int wfd = open(filename,O_WRONLY|O_CREAT|O_TRUNC,0664);
	if( wfd == -1)
	{	
		perror("open error");
		return -1;
	}
	//组装数据包
	char buf[516] = "";
	short *p1 = (short *)buf;
	*p1 = htons(1);
	
	char *p2 = buf+2;
	strcpy(p2,filename);

	char *p3 = p2+strlen(p2)+1;
	strcpy(p3,"octet");

	int len = strlen(p2) + strlen(p3) + 4;
	//向服务器发送请求包
	sendto(cfd,buf,len,0,(struct sockaddr *)&sin,sizeof(sin));
	printf("发送请求包成功\n");
	socklen_t socklen = sizeof(sin);
	while(1)
	{
		bzero(buf,sizeof(buf));
		//接收服务器返回的数据包或错误码
		int res = recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,&socklen);


		//判断服务器返回的操作码是3,代表是 数据包
		if(buf[1] == 3)
		{
			//写入到目标文件
			write(wfd,buf+4,res-4);
			//发送ACK给服务器 
			buf[1] = 4;
			sendto(cfd,buf,4,0,(struct sockaddr *)&sin,sizeof(sin));

			//判断服务器发送的数据包小于512字节,退出循环
			if(res < 516)
			{
				printf("下载完毕!!!\n");
				break;
			}
		}
		else if(buf[1] == 5)
		{
			printf("do_download error:%s\n",buf+4);
			return -1;
		}
	}
	//关闭文件描述符
	close(wfd);
	close(cfd);
	return 0;
}

//定义上传函数/***********************************************/
int do_upload(int cfd,struct sockaddr_in sin)
{
	//获取文件文件名
	char filename[40] = "";;
	printf("请输入需要上传的文件名:\n");
	scanf("%s",filename);
	getchar();
	//以只写的形式打开文件
	int rfd = open(filename,O_RDONLY);
	if( rfd == -1)
	{	
		perror("open error");
		return -1;
	}
	//组装数据包
	char buf[516] = "";
	short *p1 = (short *)buf;
	*p1 = htons(2);
	
	char *p2 = buf+2;
	strcpy(p2,filename);

	char *p3 = p2+strlen(p2)+1;
	strcpy(p3,"octet");

	int len = strlen(p2) + strlen(p3) + 4;
	//向服务器发送请求包
	sendto(cfd,buf,len,0,(struct sockaddr *)&sin,sizeof(sin));
	printf("发送请求包成功\n");
	socklen_t socklen = sizeof(sin);
	unsigned short num = 0;
	while(1)
	{
		bzero(buf,sizeof(buf));
		//接收服务器返回的应答包
		int res = recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,&socklen);
		if(buf[1] == 4)
		{
			//填充发送数据包
			if(num == ntohs(*(unsigned short*)(buf+2)))
			{	

				buf[1] = 3;
				num++;
				*(unsigned short*)(buf+2) = htons(num);
				int res1 = read(rfd,buf+4,512);
				if(res1 == 0)
				{
					printf("上传完毕\n");
					break;
				}
				//发送数据包给服务器
				sendto(cfd,buf,res1+4,0,(struct sockaddr *)&sin,sizeof(sin));

				//判断服务器发送的数据包小于512字节,退出循环
			}
			else
			{
				printf("上传失败\n");
				break;
			}
		}
		else if(buf[1] == 5)
		{
			printf("do_download error:%s\n",buf+4);
			return -1;
		}
	}
	//关闭文件描述符
	close(rfd);
	close(cfd);
	return 0;
}

/**************************** 主函数 *******************************/
int main(int argc, const char *argv[])
{
	//创建用于通信的套接字文件,返回文件描述符
	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(SERPORT);
	sin.sin_addr.s_addr = inet_addr(SERIP);

	
	//定义一个菜单选项
	int menu = -1;
	while(1)
	{
		system("clear");
		printf("\t\t======1、下载=====\n");
		printf("\t\t======2、上传=====\n");
		printf("\t\t======3、退出=====\n");
		printf("请输入选项:");
		scanf("%d",&menu);
		getchar();
		//判断用户输入的功能进行分支选择
	
		switch(menu)
		{
			case 1:
				{
					//下载功能
					do_download(cfd,sin);
				}
				break;
			case 2:
				{
					//上传功能
					do_upload(cfd,sin);
				}
			break;
			case 3: goto END;
			default:printf("您输入的选项错误,请重新输入!!!\n");
		}
		//输入任意键结束操作
		printf("请输入任意键结束!!!\n");
		while(getchar() != '\n');
	}
END:
	return 0;
}

你可能感兴趣的:(网络)