Network programming day3 homework

tftp download:

#include <myhead.h>
#define PORT 69 //目标端口号,范围1024~49151
#define IP "192.168.114.53"//目标IP

int do_download(int cfd, struct sockaddr_in sin);

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

	printf("socket creat success cfd=%d\n",cfd);
	//填充服务器的地址信息结构体,
	//真实的地址信息结构体根据地址族指定,AF_INET
	struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(PORT);//目标的端口号网络字节序1024-49151
	sin.sin_addr.s_addr = inet_addr(IP);//目标IP

	char choose = 0;
	while(1)
	{
		system("clear");
		printf("**************************\n");
		printf("***********1.下载*********\n");
		printf("***********2.上传*********\n");
		printf("***********3.退出*********\n");
		printf("**************************\n");
		printf("请输入>>>");
		scanf("%c",&choose);
		while(getchar() != 10);//循环吸收垃圾字符
		switch(choose)
		{
			case '1':
				do_download(cfd,sin);
				break;
			case '2':
				//do_upload()
				break;
			case '3'://退出
				goto END;
				break;
			default:
				printf("输入错误,请重新输入\n");

		}
		printf("输入任意字符清屏>>>");
		while(getchar() != 10);
	}


END:
	//关闭
	close(cfd);

	return 0;
}
//下载函数
int do_download(int cfd, struct sockaddr_in sin)
{
	char filename[20]="";
	printf("请输入文件名>>>");
	scanf("%s",filename);
	while(getchar() != 10);
	//组下载请求包
	char buf[516] = "";
	unsigned short* ptr1 = (unsigned short*)buf;//操作码
	*ptr1 = htons(1);

	char* ptr2 = buf+2;
	strcpy(ptr2,filename);//文件名
	
	char* ptr4 = ptr2 +strlen(filename)+1;//操作模式
	strcpy(ptr4,"octet");

	int size = 2+strlen(ptr2)+1+strlen(ptr4)+1;
	//发送下载请求包 sendto
	if(sendto(cfd, buf, size, 0, (struct sockaddr*)&sin, sizeof(sin)) < 0)
	{
		ERR_MSG("sendto");
		return -1;
	}
	printf("sendto download request success\n");

	int fd = -1;//定义一个文件描述符操控被写入的文件

	socklen_t addrlen = sizeof(sin);	
	ssize_t res = 0;
	unsigned short num = 0;//记录本地的块编号

	while(1)
	{
		//接收数据 recvfrom,接收地址信息
		if((res=recvfrom(cfd, buf, sizeof(buf), 0, (struct sockaddr*)&sin, &addrlen))<0)
		{
			ERR_MSG("recvfrom");
			return -1;
		}

		if(3 == buf[1])//数据包
		{
			if(*(unsigned short*)(buf+2) == htons(num+1))
			{
				num++;//更新本地记录的块编号
				if(-1 == fd)
				{
					if((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664)) < 0)
					{
						ERR_MSG("open");
						return -1;;
					}	
				}

				//将收到的数据写入文件
				if(write(fd, buf+4, res-4) < 0)
				{
					ERR_MSG("write");
					close(fd);
					return -1;
				}

				//发送ACK
				buf[1]=4;
				if(sendto(cfd, buf, 4, 0, (struct sockaddr*)&sin, sizeof(sin)) < 0)
				{
					ERR_MSG("sendto");
					return -1;
				}

				if(res-4 < 512)//数据小于512 则下载完成
				{
					printf("%s 下载完毕\n",filename);
					break;
				}

			}
		}
		else if(5 == buf[1]) //错误包
		{
			printf("错误: %d %s\n", ntohs(*(short*)(buf+2)), buf+4);
			close(fd);
			return -1;
		}
	}

	close(fd);
	return 0;
}


//int do_upload()

mind Mapping:

Guess you like

Origin blog.csdn.net/m0_59031281/article/details/132574909