【Linux C | 网络编程】进程池小文件传输的实现详解(二)

上一篇实现了一个最基本的进程池:客户端读取标准输入,发送给服务端,服务端回复一个相同的内容。

【Linux C | 网络编程】简易进程池的实现详解(一)

这篇内容在上篇进程池的基础上实现小文件的传输。

文件传输的本质实现上和 cp 命令的原理是一样:应用程序需要打开源文件并且进行读取,然后将读取得到的内容写入到目标文件当中。如果是远程上传/ 下载文件,则需要将前述流程分解成两个应用程序,应用程序之间使用网络传输数据。

1.文件传输流程

服务端的处理流程
  1. 监听客户端请求

    • 服务端创建监听套接字,等待客户端连接请求。
    • 当有客户端请求连接时,服务端通过accept函数接收连接,得到一个用于通信的套接字文件描述符(peerfd)。
  2. 分配任务给子进程

    • 父进程将客户端的连接分配给一个空闲的子进程,并通过进程间通信的管道传递文件描述符。
  3. 读取文件内容

    • 子进程接收到任务后,从管道中获取文件描述符(peerfd)。
    • 子进程打开需要传输的文件,并读取文件内容,将其存入发送缓冲区(sendBuf)。
  4. 发送文件名和文件内容

    • 子进程首先通过网络套接字发送文件名到客户端。
    • 然后,子进程将文件内容通过网络套接字发送到客户端。
  5. 任务完成通知

    • 文件传输完成后,子进程关闭客户端的文件描述符,并通过管道通知父进程自己已完成任务,可以接受新的任务。
客户端的处理流程
  1. 发送请求

    • 客户端向服务端发送连接请求,请求下载特定的文件。
  2. 接收文件名和文件内容

    • 客户端接收到服务端的响应后,首先读取传输过来的文件名。
    • 然后,客户端接收文件内容,并将内容存入接收缓冲区(receiveBuf)。
  3. 写入本地文件

    • 客户端将接收缓冲区中的文件内容写入本地文件系统,完成文件下载。

2.小文件的传输

所谓的小文件,就是指单次 send recv 就能发送 / 接收完成的文件。如果一端要把文件发送给另一端,要发送两个部分的数据:其一是文件名,用于对端创建文件;另一个部分是文件内容。
假设是客户端将文件上传到服务端, 一种简单的实现方法是这样的:
//客户端
//...
send(sockFd,filename,strlen(filename),0);
ret = read(fd,buf,sizeof(buf))
send(sockFd,buf,ret,0);
//...
//服务端
//...
recv(netFd,filename,sizeof(filename),0);
int fd = open(filename,O_RDONLY|O_CREAT,0666);
ret = recv(netFd,buf,sizeof(buf),0);
write(fd,buf,ret);
//...
但是这种写法会引入一个非常严重的问题,服务端在接收文件名,实际上并不知道有多长,所以它会试图把网络缓冲区的所有内容都读取出来,但是 send 底层基于的协议是 TCP 协议 —— 这是一种流式协议。 这样的情况下,服务端没办法区分到底是哪些部分是文件名而哪些部分是文件内容。完全可能会出现服务端把文件名和文件内容混杂在一起的情况,这种就是江湖中所谓的" 粘包 " 问题。
TCP的“粘包”问题详解可以看我这篇内容:
TCP粘包问题详解和解决方案【C语言】
所以接下要我们要做的事情是在应用层上构建一个私有协议,这个协议的目的是规定 TCP 发送和接收的实际长度从而确定单个消息的边界。目前这个协议非常简单,可以把它看成是一个小火车,包括一个火车头和一个火车车厢。火车头里面存储一个整型数字,描述了火车车厢的长度,而火车车厢才是真正承载数据的部分。
一个完整的文件表示:
typedef struct train_s{int size;                //火车头:记录数据长度char buf[1000];          //车厢:记录数据本身
} train_t;

 示例代码:

//transfer.c
#include "process_pool.h"#define FILENAME "small_file.txt"int transferFile(int peerfd)
{//读取本地文件int fd = open(FILENAME, O_RDONLY);ERROR_CHECK(fd, -1, "open");char buff[100] = {0};int filelength = read(fd, buff, sizeof(buff));ERROR_CHECK(filelength, -1, "read");//进行发送操作//1. 发送文件名train_t t;memset(&t, 0, sizeof(t));t.len = strlen(FILENAME);strcpy(t.buf, FILENAME);send(peerfd, &t, 4 + t.len, 0);//2. 再发送文件内容memset(&t, 0, sizeof(t));t.len = filelength;strncpy(t.buf, buff, t.len);send(peerfd, &t, 4 + t.len, 0);return 0;
}
//客户端代码: client-smallfile.c
#include <func.h>int main()
{//创建客户端的套接字int clientfd = socket(AF_INET, SOCK_STREAM, 0);ERROR_CHECK(clientfd, -1, "socket");struct sockaddr_in serveraddr;memset(&serveraddr, 0, sizeof(serveraddr));//指定使用的是IPv4的地址类型 AF_INETserveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(8080);serveraddr.sin_addr.s_addr = inet_addr("127.0.0.1");//连接服务器int ret = connect(clientfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr));ERROR_CHECK(ret, -1, "connect");printf("connect success.\n");//进行文件的接收//1. 先接收文件的名字//1.1 先接收文件名的长度int length = 0;ret = recv(clientfd, &length, sizeof(length), 0);printf("filename length: %d\n", length);//1.2 再接收文件名本身char buff[100] = {0};ret = recv(clientfd, buff, length, 0);printf("1 recv ret: %d\n", ret);int fd = open(buff, O_CREAT|O_RDWR, 0644);ERROR_CHECK(fd, -1, "open");//2. 再接收文件的内容//2.1 先接收文件内容的长度ret = recv(clientfd, &length, sizeof(length), 0);printf("fileconent length: %d\n", length);//2.2 再接收文件内容本身memset(buff, 0, sizeof(buff));ret = recv(clientfd, buff, length, 0);printf("2 recv ret: %d\n", ret);write(fd, buff, ret);close(fd);close(clientfd);return 0;
}

在头文件增加函数声明,子进程执行任务函数加入发送文件操作

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3267928.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

Java 并发编程:一文了解 Java 内存模型(处理器优化、指令重排序与内存屏障的深层解析)

大家好&#xff0c;我是栗筝i&#xff0c;这篇文章是我的 “栗筝i 的 Java 技术栈” 专栏的第 022 篇文章&#xff0c;在 “栗筝i 的 Java 技术栈” 这个专栏中我会持续为大家更新 Java 技术相关全套技术栈内容。专栏的主要目标是已经有一定 Java 开发经验&#xff0c;并希望进…

力扣高频SQL 50 题(基础版)第三题

文章目录 力扣高频SQL 50 题&#xff08;基础版&#xff09;第三题1148.文章浏览题目说明思路分析实现过程准备数据实现方式结果截图 力扣高频SQL 50 题&#xff08;基础版&#xff09;第三题 1148.文章浏览 题目说明 Views 表&#xff1a; ---------------------- | Colu…

昇思25天学习打卡营第1天|简单深度学习

前言 昇思MindSpore是一个全场景深度学习框架&#xff0c;旨在实现易开发、高效执行、全场景统一部署三大目标。 其中&#xff0c;易开发表现为API友好、调试难度低&#xff1b;高效执行包括计算效率、数据预处理效率和分布式训练效率&#xff1b;全场景则指框架同时支持云、边…

数据传输安全--SSL VPN

目录 IPSEC在Client to LAN场景下比较吃力的表现 SSL VPV SSL VPN优势 SSL协议 SSL所在层次 SSL工作原理 SSL握手协议、SSL密码变化协议、SSL警告协议三个协议作用 工作过程 1、进行TCP三次握手、建立网络连接会话 2、客户端先发送Client HELLO包&#xff0c;下图是包…

平安养老险深圳分公司:参加献血志愿者活动,点亮生命之光

7月23日&#xff0c;“热血传万里&#xff0c;家家共平安”2024年中国平安无偿献血志愿者活动启动&#xff0c;其深圳站活动于当日在深圳市福田区平安金融中心北广场举行&#xff0c;平安养老险深圳分公司积极响应活动号召参与献血&#xff0c;用行动诠释责任&#xff0c;以爱心…

Nginx 配置与优化:常见问题全面解析

文章目录 Nginx 配置与优化:常见问题全面解析一、Nginx 安装与配置问题1.1 Nginx 安装失败问题描述解决方法1.2 Nginx 配置文件语法错误问题描述解决方法二、Nginx 服务启动与停止问题2.1 Nginx 无法启动问题描述解决方法2.2 Nginx 服务无法停止问题描述解决方法三、Nginx 性能…

[Mysql-DDL数据操作语句]

目录 DDL语句操作数据库 库&#xff1a; 查看&#xff1a;show 创建&#xff1a;creat 删除&#xff1a;drop 使用(切换)&#xff1a;use 表&#xff1a; 查看&#xff1a;desc show 创建&#xff1a;create 表结构修改 rename as add drop modify change rename as …

力扣高频SQL 50题(基础版)第八题

文章目录 力扣高频SQL 50题&#xff08;基础版&#xff09;第八题1581. 进店却未进行过交易的顾客题目说明思路分析实现过程准备数据&#xff1a;实现方式&#xff1a;结果截图&#xff1a;总结&#xff1a; 力扣高频SQL 50题&#xff08;基础版&#xff09;第八题 1581. 进店…

mysql中的索引和分区

目录 1.编写目的 2.索引 2.1 创建方法 2.2 最佳适用 2.3 索引相关语句 3.分区 3.1 创建方法 3.2 最佳适用 Welcome to Code Blocks blog 本篇文章主要介绍了 [Mysql中的分区和索引] ❤博主广交技术好友&#xff0c;喜欢文章的可以关注一下❤ 1.编写目的 在MySQL中&…

【python】python大学排名数据抓取+可视化(源码+数据集+可视化+论文)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

Android开发与Java开发的共通之处:

在开始前刚好我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「Android的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01;android开发是java开发的…

JAVA.抽象、接口、内部类

1.抽象 共性&#xff0c;父类定义抽象方法&#xff0c;子类必须重写&#xff0c;或者子类也是抽象类 示例代码 animal package animalabstract;//定义抽象类animal public abstract class animal {String name;int age;//定义抽象方法eat&#xff0c;子类必须重写public abs…

OceanBase v4.2 特性解析:如何实现表级恢复

背景 在某些情况下&#xff0c;你可能会因为误操作而遇到表数据损坏或误删表的情况。为了能在事后将表数据恢复到某个特定时间点&#xff0c;在OceanBase尚未有表级恢复功能之前&#xff0c;你需要进行以下步骤&#xff1a; 利用OceanBase提供的物理恢复工具&#xff0c;您可…

昇思25天学习打卡营第23天|CV-ResNet50迁移学习

打卡 目录 打卡 迁移学习 实战练习 数据准备 数据处理 数据处理函数 数据处理流程 数据可视化 训练模型 构建Resnet50网络 固定特征进行训练 network 的输出 训练和评估 可视化模型预测 掌握迁移学习的重点在于&#xff0c;了解你的模型结构&#xff0c;通过冻结…

若依框架 : 生成代码

6.生成代码 6.1.配置生成设置 ruoyi-generator -> src -> main -> resources -> generator.yml 由于 案例中 表都有 前缀 为 tta_ , 这里设置去掉 6.2.生成代码 6.2.1.导入数据库中的表 6.2.2.修改设置 6.2.2.1.设置生成信息 点击 编辑 -> 生成信息 特别…

嵌入式Linux学习: 设备树实验

设备树&#xff08;DeviceTree&#xff09;是一种硬件描述机制&#xff0c;用于在嵌入式系统和操作系统中描述硬件设备的特性、连接关系和配置信息。它提供了一种与平台无关的方式来描述硬件&#xff0c;使得内核与硬件之间的耦合度降低&#xff0c;提高了系统的可移植性和可维…

乡下人的悲歌-感悟

这是一个最好的时代&#xff0c;也是一个最。。。的时代 前言 最近《乡下人的悲歌》一书在朋友圈火了&#xff0c;作为一个喜欢探究&#xff0c;观察生活的人&#xff0c;我想去探究这本书为什么突然爆火&#xff0c;以及作者给我们传达的什么观点&#xff0c;分享了那些&#…

Spring MVC 应用分层

1. 类名使⽤⼤驼峰⻛格&#xff0c;但以下情形例外&#xff1a;DO/BO/DTO/VO/AO 2. ⽅法名、参数名、成员变量、局部变量统⼀使⽤⼩驼峰⻛格 3. 包名统⼀使⽤⼩写&#xff0c;点分隔符之间有且仅有⼀个⾃然语义的英语单词. 常⻅命名命名⻛格介绍 ⼤驼峰: 所有单词⾸字⺟…

笔试编程算法题笔记(三 C++代码)

1.kotori和n皇后 题意简单来说就是&#xff0c;在一个无穷大的棋盘上&#xff0c;不断插入k个皇后&#xff0c;皇后们如果在 同一行&#xff0c;同一列&#xff0c;在一个45主对角线 在一个135副对角线上&#xff0c;就可以互相攻击。 我们需要判断在第i个皇后插入后&#xff…

【STM32本科毕业设计】基于STM32的多功能MP3播放器设计

目录 一. 概述二. 系统硬件设计2.1 整体设计思路2.2 硬件器件的选择2.2.1 MP3解码芯片选择 2.2.2 收音机芯片选择2.2.3 温度传感器选择2.2.4 彩灯驱动芯片选择2.2.5 音效处理芯片选择2.2.6 EEPROM芯片选择2.2.7 功率放大芯片选择2.2.8 电源芯片选择2.2.9 人机交互设备选择 2.3 …