day37 1219

作业1:tftp

#include

//实现下载功能
int do_download(int cfd, struct sockaddr_in sin)
{
    //定义变量存储下载请求包
    char buf[516] = "";
    //定义变量存储文件名
    char fileName[40] = "";

    printf("请输入文件名:");
    scanf("%s", fileName);
    getchar();

    //组装请求包
    short *p1 = (short *)buf;
    *p1 = htons(1);                 //表明要下载

    char *p2 = buf+2;           //文件名段
    strcpy(p2, fileName);

    char *p4 = p2+strlen(p2)+1;    //模式段
    strcpy(p4, "octet");

    int size = 4 + strlen(p2) + strlen(p4);      //要发送数据的大小
    
    //向服务器发送下载请求
    if(sendto(cfd, buf, size, 0, (struct sockaddr*)&sin, sizeof(sin)) == -1)
    {
        perror("sendto error");
        return -1;
    }

    printf("请求成功\n");
	
	struct sockaddr_in newsin;
	socklen_t socklen = sizeof(newsin);
	
	int res = 0;
	int fd = -1;
	fd = open(fileName,O_WRONLY|O_CREAT|O_TRUNC,0664);
	PERROR_INFO(fd);

    //循环接收回复服务器发来的消息
	while (1)
	{
		bzero(buf,sizeof(buf));
	    res = recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr *)&newsin,&socklen);
		
		//printf("*p1 = %d\n",ntohs(*p1));

		if (ntohs(*p1) == 3)
		{
			write(fd,buf+4,res-4);	

			buf[1] = 4;

			if(sendto(cfd,buf,4,0,(struct sockaddr*)&newsin,sizeof(newsin)) == -1)
			{
				perror("sendto error");
				return -1;
			}
		}
		else if (buf[1] == 5)
		{
			printf("5 error\n");
			return -1;
		}

		if (res < 516)
		{
			puts("file is clone over!!!");
			close(fd);
			break;
		}
		
	}
    close(fd);
    return 0;
 
}

int do_upload(int cfd, struct sockaddr_in sin)
{
     //定义变量存储下载请求包
    char buf[516] = "";
    //定义变量存储文件名
    char fileName[40] = "";

    printf("请输入文件名:");
    scanf("%s", fileName);
    getchar();

    //组装请求包
    short *p1 = (short *)buf;
    *p1 = htons(2);                 //表明要上传

    char *p2 = buf+2;           //文件名段
    strcpy(p2, fileName);

    char *p4 = p2+strlen(p2)+1;    //模式段
    strcpy(p4, "octet");

    int size = 4 + strlen(p2) + strlen(p4);      //要发送数据的大小
    
    //向服务器发送下载请求
    if(sendto(cfd, buf, size, 0, (struct sockaddr*)&sin, sizeof(sin)) == -1)
    {
        perror("sendto error");
        return -1;
    }

    printf("请求成功\n");
    ///p5指向块编号的字节
    ///p1指向前两个字节
    short *p5 = p1+1;
    bzero(buf,sizeof(buf));
    socklen_t socklen = sizeof(sin);
    recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,&socklen);

    printf("port = %d\n",ntohs(sin.sin_port));
    printf("第0次:%d\n",ntohs(*p1));
    ///确认服务器接收到上传请求,发挥给我的ACK应答包前两个字节是4,然后是块编号是0
    ///下面收发数据块编号从1开始
    if (ntohs(*p1) == 4 && ntohs(*p5) == 0)
    {
        printf("收到服务器应答包\n");
    }

    int fd = -1;
    fd = open(fileName,O_RDONLY);
    PERROR_INFO(fd);

    int res = -1;
    ///定义块编号
    int count = 1;
    
    
    while (1)
    {
        bzero(buf,sizeof(buf));
        res = read(fd,buf+4,512);
        
        //两种方式,将前两个字节修改为3,表示这个包为数据包
        //将块编号修改为count
        *p5 = htons(count); 
        buf[1] = 3;
        
        //发送数据包
        sendto(cfd,buf,res+4,0,(struct sockaddr*)&sin,sizeof(sin));
        //接收服务器返回的应答包
        recvfrom(cfd,buf,4,0,(struct sockaddr*)&sin,&socklen);

        printf("第%d次:p1 = %d,p5 = %d,res = %d\n",count,ntohs(*p1),ntohs(*p5),res);
        //判断前两个字节是不是4,如果是的话,就是应答包,再判断块编号与发送过去的是否一致
        if (ntohs(*p1) == 4&&ntohs(*p5) == count)
        {
            printf("收到%d应答包\n",count);
            if (res < 512)
            {
           
                printf("发送结束\n");
                break;
            }
            //当确认收到了应答包之后,块编号++,继续发送下一块
            count++;
        }
        else 
        {
            //如果服务器返回的应答包不对,则跳出循环
            printf("error!!!!!!\n");
            return 0;
        }
    }
    close(fd);
    return 0;
    
}

int main(int argc, const char *argv[])
{
    if(argc != 2)
    {
        printf("input error\n");
        printf("usage:./a.out ip\n");
        return -1;
    }

    //1、创建套接字
    int cfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(cfd == -1)
    {
        perror("socket error");
        return -1;
    }

    //2、填充服务器地址信息结构体
    struct sockaddr_in sin;
	sin.sin_family = AF_INET;
    sin.sin_port = htons(69);
    sin.sin_addr.s_addr = inet_addr(argv[1]);

    int mune = -1;
    while(1)
    {
        system("clear");                     //清屏
        printf("\t\t======1、下载=======\n");
        printf("\t\t======2、上传=======\n");
        printf("\t\t======0、退出=======\n");

        printf("请输入功能:");
        scanf("%d", &mune);
        getchar();

        //多分支选择
        switch(mune)
        {
        case 1:
            {
                do_download(cfd, sin);
            }
            break;

        case 2:
            {
                do_upload(cfd,sin);
            }
            break;
        case 0:
            goto POS;
        default:printf("输入功能有误,请重新输入\n");
        }

        //阻塞
        printf("输入任意键,按回车清空:");
        while(getchar() != '\n');

    }

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


    return 0;
}

思维导图

你可能感兴趣的:(算法)