网络安全实验一 Part 1 编写Linux下的C/S文件传输程序

实验任务

  • 实现一个CS模式的文件传输应用,要求

    1. 客户端可以向服务器上传文件
    2. 客户端可以获取服务器文件列表,并下载指定文件
  • 效果示例 (源码)

    在这里插入图片描述

    在这里插入图片描述

实验步骤一、确定传输协议

  • 作为一个双向文件传输的C/S应用,必须规定双方交流的规则,也就是协议的语法、语义、时序

  • 协议格式:操作码(ASCII字符) + 信息

    在这里插入图片描述

    其中

    • close connection \text{close connection} close connection o p t = 0 opt = 0 opt=0,客户端发起,结束连接
    • client → 文 件 server \text{client} \xrightarrow{文件} \text{server} client server o p t = 1 opt = 1 opt=1,由客户端发送请求,服务器返回确认,之后进入文件传输
    • client ← 文 件 列 表 server \text{client} \xleftarrow{文件列表} \text{server} client server o p t = 2 opt = 2 opt=2,对于下载服务器文件,首先要请求文件列表,服务器返回文件数量及文件名列表,每个文件名长度为32字节
    • client ← 文 件 server \text{client} \xleftarrow{文件} \text{server} client server o p t = 4 opt = 4 opt=4,客户端指定文件,服务器返回文件长度,之后进入文件传输
    • file transfer \text{file transfer} file transfer o p t = 5 opt=5 opt=5,操作码后跟4字节的传输内容长度,从第五个字节开始是传输的内容主体
  • 协议封装及提取实现示例:服务器封装文件列表,客户端提取

    server.c

    void sendFileList(SOCK conn) {
        
        int fileCount = 0; /* 记录文件数量 */
        char sendBuf[BUFSIZE] = {0}; /* 发送缓冲区 */
        sendBuf[0] = '2'; /* 首字节为'2',返回文件列表 */
        
        /* 目录获取文件列表*/
        DIR* dir;
        if((dir = opendir(".")) == NULL) {
            printf("open dir error(%d): %s\n");
            exit(0);
        }
        struct dirent *ent;
        while((ent = readdir(dir)) != NULL) {
            if(ent->d_type == 8) {
                /* 将文件名拷贝至发送缓冲区中,每个文件名占32字节 */
                strncpy(sendBuf + 5 + (fileCount++) * 32, ent->d_name, strlen(ent->d_name) + 1);
            }
        }
        
        /* 将文件数量填充至第2个字节开始的四个字节中 */
        *(int *)(sendBuf + 1) = fileCount;
        
        /* 向服务器发送按协议格式封装的文件列表 */
        if(send(conn, sendBuf, 5 + 32 * fileCount, 0) == -1) {
            printf("send error(%d): %s\n", errno, strerror(errno));
            exit(0);
        }
    }
    

    client.c

    void sendFileListRequest(SOCK conn) {
        
        /* 发送获取服务器文件列表请求 */
        char sendBuf[BUFSIZ] = {0}; /* 请求缓冲区 */
        sendBuf[0] = '2'; /* opt=2 请求服务器文件列表 */
        if(send(conn, sendBuf, 1, 0) == -1) {
            printf("send error(%d): %s\n", errno, strerror(errno));
            exit(0);
        }
        
        /* 解析服务器响应 */
        char recvBuf[BUFSIZE] = {0}; /* 接收缓冲区 */
        int recvLen;
        if((recvLen = recv(conn, recvBuf, sizeof(recvBuf), 0)) == -1) {
            printf("recv error(%d): %s\n", errno, strerror(errno));
            exit(0);
        }
        
        /* 根据协议,服务器返回的首字节应为 opt=2 */
        if(recvBuf[0] != '2') {
            printf("unknown error\n");
            exit(0);
        }
        /* 获取文件数量 */
        int fileCount = *(int *)(recvBuf + 1);
        printf("%d\n", fileCount);
        int i;
        /* 循环输出文件名,每个文件名占32字节,可依次定位文件名地址 */
        for(i = 0; i < fileCount; i++) {
            printf("%d. %s\n", i + 1, recvBuf + 5 + i * 32);
        }
    }
    

实验步骤二、服务器实现

  • 主程序

    int main() {
    
        /* 创建server socket并设置监听 略 */
        printf("监听中......\n");
    
        /* 客户端地址信息 */
        int addrLen = sizeof(connAddr); // 这个客户端地址长度一定要初始化,不然无法记录地址信息
        char addrBuf[32] = {0};
        
        /* 等待客户端连接 */
        while(1) {
            /* 接收客户端连接 */
            if((conn = accept(server, (struct sockaddr*)&connAddr, &addrLen)) == -1) {
                printf("accept connection error(%d): %s\n", errno, strerror(errno));
                continue;
            }
            /* 输出客户端地址信息 */
            if(inet_ntop(AF_INET, &connAddr.sin_addr, addrBuf, sizeof(addrBuf)) == NULL) {
                printf("net address errro(%d), %s\n", errno, strerror(errno));
                exit(0);
            }
            printf("接收到连接请求: %s!\n连接成功!\n", addrBuf);
            /* 处理客户端请求 */
            responde(conn);
        }
    
        /* 释放socket资源 略 */
    
        return 0;
    }
    
  • 响应主程序

    void responde(SOCK conn) {
        
        char recvBuf[BUFSIZE];
        int recvLen;
        int closed = 0; /* 客户端断开连接标志 */
    	
        /* 循环处理客户端请求 */
        while(1) {
            if(closed) break;
    		
            /* 获取客户端请求 */
            if((recvLen = recv(conn, recvBuf, sizeof(recvBuf), 0)) == -1) {
                printf("recv errro(%d): %s\n", errno, strerror(errno));
                exit(0);
            }
            /* 解析客户端请求 */
            switch (recvBuf[0])
            {
                case '0':
                    close(conn);
                    closed = 1;
                    printf("本次连接关闭!等待下个连接\n");
                    break;
                case '1':
                    printf("接受文件: %s 文件大小: %d字节\n", recvBuf + 1, *(int *)(recvBuf + 33));
                    recvFile(conn, recvBuf + 1, *(int *)(recvBuf + 33));
                    break;
                case '2':
                    printf("收到下载请求!\n");
                    sendFileList(conn);
                    break;
                case '4':
                    sendFile(conn, recvBuf + 1);
                    break;
                default:
                    break;
            }
        }
    }
    
  • 功能实现:按照协议实现即可

实验步骤三、客户端实现

  • 提示信息

    char divider[] = {
        "=========================================\n"
    };
    char options[] = {
        "欢迎来到文件系统,请选择需要的功能:\n"
        "send:          向服务器传送一个文件\n"
        "download:      从服务器下载一个文件\n"
        "quit:          退出程序\n"
    };
    char inputTip[] = {
        "请输入操作指令: "
    };
    
  • 主程序

    int main(int argc, char *argv[]) {
        
        if(argc != 2) {
            printf("请输入服务器IP地址...\n");
            exit(0);
        }
        
        /* 解析服务器地址 */
        if(inet_pton(AF_INET, argv[1], &servAddr.sin_addr) == -1) {
            printf("net address error(%d): %s\n", errno, strerror(errno));
            exit(0);
        }
    
        /* 创建client socket 略 */
    
        /* 连接服务器 */
        if((connect(client, (struct sockaddr*)&servAddr, sizeof(servAddr))) == -1) {
            printf("connect to server error(%d): %s\n", errno, strerror(errno));
            exit(0);
        }
    
        /* 发起请求 */
        request(client);
    
        /* 释放socket资源 略 */
        
        return 0;
    }
    
  • 请求主程序

    void request(SOCK conn) {
    
        char option[32] = {0};
        char fileName[32] = {0};
        /* 循环发起请求 */
        while(1) {
            /* 打印提示信息 */
            printf("%s%s%s", divider, options, inputTip);
            scanf("%s", option);
            switch (option[0])
            {
            case 's':
                printf("请输入要传送的文件名:");
                scanf("%s", fileName);
                sendFile(conn, fileName);
                break;
            case 'd':
                printf("服务器端的文件列表:\n");
                sendFileListRequest(conn);
                printf("请输入需要下载的文件名:");
                scanf("%s", fileName);
                downloadFile(conn, fileName);
                break;
            case 'q':
                sendCloseRequest(conn);
                return ;
            default:
                break;
            }
        }
    }
    
  • 功能实现:按照协议实现即可

总结

  • 时间比较紧,客户端和服务器的不少代码是重复的,也比较乱,以后有时间再整理
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LinuxLinux-4.9.88/drivers/pinctrl目录结构如下: - core.c:pinctrl核心代码,包括pinctrl设备的注册与注销、pin和pin group的获取、配置和释放等。 - pinctrl-utils.c:pinctrl工具函数,例如获取pin的名称、通过pin的名称获取pin等。 - pinmux.c:pinmux子系统代码,包括pinmux设备的注册与注销、pinmux的获取、配置和释放等。 - pinctrl-single.c:pinctrl单例驱动,用于不需要动态配置pin的平台。 - pinconf.c:pin配置子系统代码,包括pin配置设备的注册与注销、pin配置的获取、配置和释放等。 - pinconf-generic.c:pin配置的通用实现,处理通用的pin配置属性。 - pinconf-sunxi.c:Allwinner SoC的pin配置实现。 - pinconf-tegra.c:Nvidia Tegra SoC的pin配置实现。 - pinconf-intel.c:Intel SoC的pin配置实现。 - pinconf-mcp23s08.c:Microchip MCP23S08 GPIO扩展器的pin配置实现。 - pinconf-mcp23s17.c:Microchip MCP23S17 GPIO扩展器的pin配置实现。 - pinconf-mcp23s18.c:Microchip MCP23S18 GPIO扩展器的pin配置实现。 - pinconf-rza1.c:Renesas RZ/A1 SoC的pin配置实现。 - pinconf-rza2.c:Renesas RZ/A2 SoC的pin配置实现。 - pinconf-rza2-part1.c:Renesas RZ/A2M SoC的pin配置实现。 - pinconf-rza2-part2.c:Renesas RZ/A2H SoC的pin配置实现。 总体来说,pinctrl文件夹下的代码实现了pin、pinmux和pin配置子系统的功能,同时提供了一些通用和特定SoC的实现。这些代码是用于Linux内核中进行GPIO和pin控制的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值