2024.1.16 网络编程 作业

思维导图

练习题

1.基于UDP的TFTP文件传输,实现文件下载上传

cpp 复制代码
#include <myhead.h>

int main(int argc, char const *argv[])
{
    // 创建套接字UDP通信
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (-1 == sockfd)
    {
        perror("socket error");
        return -1;
    }
    // 填充服务器网络信息结构体
    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    //端口号填69
    sin.sin_port = htons(69);
    //填写windows ip地址
    sin.sin_addr.s_addr = inet_addr("192.168.124.19");
    //结构体长度
    socklen_t socklen = sizeof(sin);

    //数据包数据的长度以512字节传输
    char buffer[516] = {0};
    //返回的ACK
    char ack[4];
    //操作码
    short code = 0;
    //块编号 or 错误码
    short BlockoErr = 0;
    //数据的长度以512Byte传输
    char text[512] = {0}; //文件内容 或 错误信息
    //校验收到的块编号
    int N = 0;
    //返回的文件描述符
    int fd;
    int ret = 0;

    //输入文件名
    char filename[64] = {0};
    printf("下载文件名: ");
    scanf("%s", filename);

    //使用 sprintf 组包
    //返回成功格式化字符的个数
    ret = sprintf(buffer, "%c%c%s%c%s%c", 0, 1, filename, 0, "octet", 0);

    //首次发送请求
    if (-1 == sendto(sockfd, buffer, ret, 0, (struct sockaddr *)&sin, socklen))
    {
        perror("sendto error");
        return -1;
    }
    //循环接收服务器发来的数据包
    while (1)
    {
        //因为有临时端口需要保存服务器的网络信息结构体
        ret = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&sin, &socklen);
        if (-1 == ret)
        {
            perror("recvfrom error");
            return -1;
        }

        //解析操作码
        code = ntohs(*(short *)buffer);
        //解析块编号or错误码
        BlockoErr = ntohs(*(short *)(buffer + 2));
        //解析文件内容or错误信息,并将内容放入数据段
        strncpy(text, buffer + 4, sizeof(text));
        //解析数据包中的内容
        if (3 == code && BlockoErr == N + 1)
        {
            //校验块编号+1
            N++;
            //要接收的数据包
            //如果是第一次接到数据包 要创建文件
            if (BlockoErr == 1)
            {
                fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664);
                if (-1 == fd)
                {
                    perror("open error");
                }
            }
            //将文件内容写入文件 ret是buffer中去掉前4字节操作数和块编号所剩余的内容
            if (-1 == write(fd, text, ret - 4))
            {
                perror("write error");
            }
            // 组装ACK
            *(short *)ack = htons(4);
            *(short *)(ack + 2) = htons(BlockoErr);
            //回复ACK包
            if (-1 == sendto(sockfd, ack, 4, 0, (struct sockaddr *)&sin, socklen))
            {
                perror("recvfrom error");
            }
            //文件接收完毕
            if (ret < 512)
                break;
        }
    }

    printf("文件[%s]下载完成\n", filename);
    close(sockfd);
    return 0;
}
相关推荐
Yurko1312 小时前
【计网】基于三层交换机和 RIP 协议的局域网组建
网络·学习·计算机网络·智能路由器
无序的浪12 小时前
网络初识~
网络
wzlsunice8813 小时前
用vir-manager创建kvm虚拟机(创建网桥和配置网络等)
运维·网络
思茂信息13 小时前
CST License(Flexnet)设置与问题处理方法
服务器·网络·单片机·3d·php·1024程序员节·cst
m0_7381207213 小时前
内网横向靶场——记录一次横向渗透(三)
开发语言·网络·安全·web安全·网络安全·php
Jerry25050914 小时前
微信小程序必要要安装SSL证书吗?小程序SSL详解
网络·网络协议·网络安全·微信小程序·小程序·https·ssl
大G的笔记本15 小时前
gRPC vs RPC 高频面试题
网络·网络协议·rpc
无敌最俊朗@15 小时前
7层/4层模型讲解
网络
代码程序猿RIP16 小时前
【Linux面经】OSI七层模型和TCP/IP四层体系结构
linux·网络·面试·面经
njnu@liyong16 小时前
HTTP-发展史
网络·网络协议·http