125_TFTP协议编程_基于UDP协议_客户端(虚拟机)不带选项,发送组写请求,向服务器(tftpd32所在文件夹)写文件案例【使用基础函数、✳3.2组写的介绍+伪代码实现✳】

图片:

125_TFTP协议编程_基于UDP协议_客户端(虚拟机)不带选项,发送组写请求,向服务器(tftpd32所在文件夹)写文件案例【使用基础函数、✳3.2组写的介绍+伪代码实现✳】

#if 1 //-----------组【写】请求-------------//

int main()
{

    //创建套接字
    int sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sock_fd < 0)
    {
        perror("error");
    }
    else
    {
        printf("创建成功! %d\n", sock_fd);//文件描述符0 1 2已被使用,最小就是3开始
    }

    //【虚拟机】给【服务器Tptpd32】发送【上传】a.txt的请求
    //服务器就是我们的Tptpd32工具
    //他的IP是我们的本机IP:10.36.145.91
    //端口固定69
    //给【特定端口、IP】发送请求
    struct sockaddr_in ser_addr;
    ser_addr.sin_family = AF_INET;
    ser_addr.sin_port = htons(69); //指定端口  69,虚拟机下都是小端,转成window下识别的大端数据
    inet_pton(AF_INET, "10.36.145.91", (void *)&ser_addr.sin_addr);//指定IP,点分十进制,转成32位无符号整数,window下识别的IP数据

    //组【写】请求
    char buf[64] = "";
    int buf_len = sprintf(buf, "%c%c%s%c%s%c", 0, 2,"a.txt", 0, "netascii", 0);
    //把组写请求,发送到服务器上
    //等待服务器回应
    sendto(sock_fd, buf, buf_len, 0, (struct sockaddr *)&ser_addr, sizeof(ser_addr));

    //打开本地文件
    int fd = open("a.txt", O_RDWR);
    if(fd < 0)
    {
        perror("error");
        return 0;
    }


    //接收数据包
    char rec_buf[1024] = "";//不能小于516
    int rec_buf_len = 0;
    unsigned short p_num = 0;//short类型占两个字节,计算【块编号】


    //存储服务器的信息-----交流的时候服务器的端口,一直是【动态】的
    struct sockaddr_in from_addr;
    socklen_t addrlen = sizeof(from_addr);

    while(1)
    {        
        bzero(&from_addr, sizeof(from_addr));

        //上面发送了写信息
        //会从服务器接收到ACK的包信息:[0 4 0 0],存进rec_buf数组
        recvfrom(sock_fd, rec_buf, sizeof(rec_buf), 0,\
                            (struct  sockaddr*)&from_addr, &addrlen);

        
        //根据操作码的第二位的标志位判定
        //接收出差错了
        if(rec_buf[1] == 5)
        {
            printf("error = %s\n", rec_buf + 4);
            break;
        }
        else if(rec_buf[1] == 4)
        {//先收到一次ACK[0 4 0 0]---->然后发送数据包,数据包构成:[0 3 0 1 512byte]
         //[0 3 0 1]:操作位+块编号
         //512byte:一次上传服务器内容大小

            //跳过[0 4 0 0]前四位【操作码、块编号】
            //把文件内容读到数组中,读512字节数据
            rec_buf_len = read(fd, rec_buf + 4, 512);

            //在网络层通过IP进行信息交互
            //数据格式需要改变!!!



            //ACK收到,开始发送数据包
            rec_buf[1] = 3;

            //接收到一个,需要对块编号,进行++了
            //unsigned short * :拿到编号位short两个字节的[0 0]的首地址,
            //取地址,把计算后的值 0 赋值给p_num
            //先在客户端【虚拟机】上,对数据包的块编号+1,
            //且需要对之前从服务器接收到的大端【块编号】,进行小端处理才行   
            p_num = ntohs( *(unsigned short *)(rec_buf + 2));

            //p_num + 1  得到--->1
            //再计算完成后
            //转成服务器适用的【大端】数据
            //1 变成 [0 1],第一位补0,完成块编号的++操作
            *(unsigned short *)(rec_buf + 2) = htons(p_num + 1);
            printf("即将发送数据包编号:%d\n",p_num+1);

            //发送的数据,去除【操作码、块编号】的四个字节
            sendto(sock_fd, rec_buf, rec_buf_len + 4, 0, (struct  sockaddr*)&from_addr,sizeof(from_addr));
            if(rec_buf_len < 512)
            {
                printf("文件读取完\n");
                break;
            }
        }

   
    }


    close(sock_fd);
    close(fd);




    return 0;
}

#endif

上一篇:TFTP系统下载上传TXT文件(不带选项)


下一篇:invalid memory address处理