网络编程 8月10日

tftp客户端下载

代码

int do_download(int cfd, struct sockaddr_in sin)
{
    //发送下载请求
    char buf[N] = "";
    char filename[N - 10] = "";
    printf("请输入需要下载的文件>>> ");
    scanf("%s", filename);
    while(getchar() != 10);

    unsigned short *p1 = (unsigned short *)buf;
    *p1 = htons(1);

    char *p2 = buf + 2;
    strcpy(p2, filename);

    char *p3 = p2 + strlen(p2);
    *p3 = 0;

    char *p4 = p3 + 1;
    strcpy(p4, MODE);

    int size = 2 + strlen(p2) + 1 + strlen(p4) + 1;
    if (sendto(cfd, buf, sizeof(buf), 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
    {
        ERR_MSG("sendto");
        return -1;
    }
    
    //打开文件,用于存储下载后的文件
    int fd = -1;    //必须初始化成一个无效的文件描述符

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

    while (1)
    {
        bzero(buf, sizeof(buf));
        //接收数据
        res = recvfrom(cfd, buf, sizeof(buf), 0, (struct sockaddr *)&sin, &addrlen);
        if (res < 0)
        {
            ERR_MSG("recvfrom");
            return -1;
        }
        
        //printf("%d %d %d %d | %d %d\n", buf[0], buf[1], buf[2], buf[3], ntohs(*(short *)buf), ntohs(*(short *)(buf + 2)));
        //由于操作码占两个字节,且是个大端字节序
        //所以低字节存储在高地址,高字节存储在低地址
        //所以有效操作码,存储在高地址上,即buf[1]的位置

        if (3 == buf[1])    //数据包
        {
            //判断服务器返回的数据包的块编号与本地记录的块编号是否一致
            if (*(unsigned short *)(buf + 2) == htons((num + 1)))
            {
                num++;  //更新本地记录的块编号

                if (-1 == fd)
                {
                    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664);
                    if (fd < 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;
                }
                
                //若接收到的数据小于512,则跳出循环,结束下载
                if ((res - 4) < 512)
                {
                    printf("---%s 文件下载完毕---\n", filename);
                    break;
                }
            }
        }
        else if (5 == buf[1])   //错误包
        {
            printf("---ERROR: %d %s---\n", ntohs(*(short *)(buf + 2)), buf + 4);
            close(fd);
            return -1;
        }
    }

    close(fd);
    
    return 0;
}

结果

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值