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;
}
相关推荐
晚秋大魔王2 小时前
windwos与linux环境下Iperf3带宽测试工具的安装、使用
网络·iperf3·带宽测试
多敲代码防脱发3 小时前
Spring框架基本使用(Maven详解)
java·网络·后端·spring·maven
wssswsss3 小时前
docker容器网络配置及常用操作
网络·docker·容器
RFID舜识物联网4 小时前
RFID测温技术:电力设备安全监测的新利器
网络·人工智能·嵌入式硬件·物联网·安全
靖节先生5 小时前
Wireshark详解
网络·测试工具·wireshark
技术小齐6 小时前
网络运维学习笔记 021 HCIA-Datacom新增知识点02 SDN与NFV概述
运维·网络·学习
ZachOn1y8 小时前
计算机网络:应用层 —— 域名系统 DNS
网络·计算机网络·应用层·408考研·知识积累·域名系统dns
给生活加糖!10 小时前
智能交通系统(Intelligent Transportation Systems):智慧城市中的交通革新
网络·人工智能·智慧城市
人间打气筒(Ada)10 小时前
ubuntu网络及软件包管理
网络·ubuntu·php
明达技术11 小时前
工控自动化领域:数字量信号与模拟量信号的差异解析
网络