8.29网络编程作业

#include<myhead.h>

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

#define SER_PORT 69
#define SER_IP  "192.168.101.49"

int do_download(int cfd, struct sockaddr_in sin);

int main(int argc, const char *argv[]) 
{
	//创建报式套接字文件
	int cfd = socket(AF_INET, SOCK_DGRAM, 0);
	if(cfd < 0)
	{
	    ERR_MSG("socket");
		return -1;
	}
	printf("socket create success cfd=%d\n", cfd);

	//填充服务器的地址信息结构体,给dento函数使用
	//真实的地址信息结构体根据地址族指定, AF_INET:man 7 IP
	struct sockaddr_in sin;
	sin.sin_family        = AF_INET;
	sin.sin_port          = htons(SER_PORT);
	sin.sin_addr.s_addr   = inet_addr(SER_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");
				break;
		}

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

END:

	//关闭套接字
	close(cfd);

	return 0;
}


int do_download(int cfd, struct sockaddr_in sin)
{
    char buf[516] = "";
	char filename[20] = "";

	printf("请输入要下载的文件名>>>");
	scanf("%c",filename);
	while(getchar()!=10);

    //组下载请求包,
	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");

	unsigned short k = 0;   //本地记录的块编号
	int fd;            //初始化文件描述符
	socklen_t addrlen = sizeof(sin);
	ssize_t res = 0;

	while(1)
	{
	    memset(buf, 0, sizeof(buf));     //清空
	    //接收数据 recvfrom, 接收地址信息
		if((res = (recvfrom(cfd, buf, sizeof(buf), 0, (struct sockaddr*)&sin, &addrlen))) < 0)
		{
		    ERR_MSG("recefrom");
			return -1;
		}
		
		if(3 == buf[1])
		{
		    //UDP会数据重复,防止重复收包
			//记录传过来的块编号,判断每次编号是否正确
			if(htons(k+1) == *(unsigned short*)(buf+2))
			{
			       k++;
				   if((fd=open("01test.c",O_WRONLY|O_CREAT|O_TRUNC, 0664)) < 0)
				   {
					    ERR_MSG("open");
						return -1;
				   }
				}

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

				//组ACK sendto
				buf[1] = 4;
				if(sendto(cfd, buf, 4, 0, (struct sockaddr*)&sin, sizeof(sin)) < 0)
				{
				    ERR_MSG("sendto");
					return -1;
				}
				//判断数据是否小于512,若小于则下载完成
				if(res-4 < 512)
				{
				    printf("文件下载完成\n");
					break;
				}
			}
		
		//错误包
		if(5 == buf[1])
		{
		    printf("MSG_ERR: code[%d] msg[%s] __%d__\n",\
					ntohs(*(unsigned short*)(buf+2)), buf+4,  __LINE__);
					break;
		}
	}

	close(fd);
	close(cfd);

	return 0;
}

猜你喜欢

转载自blog.csdn.net/JunCool02/article/details/132570058