基于Linux的多进程并发服务器设计与实现

基于Linux的多进程并发服务器设计与实现

简介

本项目实现了一个基于Linux的多进程并发服务器框架,采用进程池技术提高服务器并发处理能力,主要用于文件传输服务。该框架利用了Unix域套接字、管道通信、文件描述符传递和epoll机制等技术,实现了高效的任务分发和并发处理。

系统架构

该服务器采用主-从进程模型(Master-Worker模式):

  • 主进程(Master进程):负责监听客户端连接请求,并将连接分发给空闲的子进程
  • 子进程(Worker进程):负责处理具体的业务逻辑,如文件传输

系统架构图如下:

+------------------+
|   主进程(Master)  |
|    监听连接请求    |
|    分发任务给子进程 |
+--------+---------+|   |   ||   |   |v   v   v
+-----+ +-----+ +-----+
|子进程1| |子进程2| |子进程n|
|处理业务| |处理业务| |处理业务|
+-----+ +-----+ +-----+

关键技术

进程池设计

进程池是预先创建一组子进程,这些进程等待主进程分配任务。此设计可避免频繁创建和销毁进程的开销,提高系统响应速度。

// 进程状态定义
typedef enum worker_status
{FREE = 0,  // 空闲状态BUSY       // 忙碌状态
} worker_status_t;// 进程数据结构
typedef struct
{pid_t pid;              // 子进程IDint pipefd;             // 与父进程通信的管道worker_status_t status; // 子进程当前状态
} process_data_t;

进程间通信

本项目使用Unix域套接字(socketpair)实现父子进程间的双向通信:

int makechild(process_data_t *p, int num)
{for (int i = 0; i < num; i++){int pipefd[2];socketpair(AF_LOCAL, SOL_SOCKET, 0, pipefd); // 创建全双工通信管道pid_t pid = fork();if (pid == 0){close(pipefd[1]); // 子进程关闭写端handleTask(pipefd[0]);exit(0);}else{close(pipefd[0]); // 父进程关闭读端// 保存子进程信息p[i].pid = pid;p[i].pipefd = pipefd[1];p[i].status = FREE;}}return 0;
}

文件描述符传递

使用 sendmsg/recvmsg 系统调用,通过 SCM_RIGHTS 控制消息传递文件描述符,实现父进程将客户端连接传递给子进程:

int sendfd(int pipefd, int fd)
{char buf[4] = {0};struct iovec iov;iov.iov_base = buf;iov.iov_len = sizeof(buf);size_t len = CMSG_LEN(sizeof(fd));struct cmsghdr *cmsg = (struct cmsghdr *)calloc(1, len);cmsg->cmsg_len = len;cmsg->cmsg_type = SCM_RIGHTS;  // 设置类型为传递文件描述符cmsg->cmsg_level = SOL_SOCKET;int *p = (int *)CMSG_DATA(cmsg);*p = fd;  // 填入要传递的文件描述符struct msghdr msg;memset(&msg, 0, sizeof(msg));msg.msg_iov = &iov;msg.msg_iovlen = 1;msg.msg_control = cmsg;msg.msg_controllen = len;sendmsg(pipefd, &msg, 0);free(cmsg);return 0;
}

I/O多路复用

使用epoll机制监听多个文件描述符,提高I/O效率:

int epolladdfd(int epfd, int fd)
{struct epoll_event ev;bzero(&ev, sizeof(ev));ev.events = EPOLLIN; // 监听读事件ev.data.fd = fd;int ret = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);ERROR_CHECK(ret, -1, "epoll_ctl error");return 0;
}

工作流程

  1. 初始化阶段

    • 主进程创建指定数量的子进程
    • 每个子进程与主进程建立管道通信
    • 子进程进入事件循环,等待任务
  2. 连接处理阶段

    • 主进程监听客户端连接
    • 客户端请求到达时,主进程通过epoll监测到连接事件
    • 主进程接受连接,获取客户端socket描述符
  3. 任务分发阶段

    • 主进程寻找空闲子进程
    • 主进程通过sendfd将客户端socket描述符传递给子进程
    • 主进程将子进程状态设置为BUSY
  4. 任务处理阶段

    • 子进程通过recvfd接收客户端socket描述符
    • 子进程处理文件传输业务
    • 任务完成后,子进程关闭客户端socket描述符
    • 子进程向主进程发送完成信号
  5. 任务完成阶段

    • 主进程接收到子进程的完成信号
    • 主进程将子进程状态重新设置为FREE
    • 子进程可以继续处理新的任务

文件传输实现

文件传输采用分块传输方式,确保大文件也能高效传输:

int transferfile(int peerfd)
{// 打开文件int fd = open(FILENAME, O_RDWR, 0777);// 发送文件名int namelen = strlen(FILENAME);sendn(peerfd, &namelen, sizeof(namelen));sendn(peerfd, FILENAME, namelen);// 发送文件大小struct stat st;fstat(fd, &st);sendn(peerfd, &st.st_size, sizeof(st.st_size));// 分块发送文件内容char buf[1000] = {0};off_t sent = 0;while (sent < st.st_size){int ret = read(fd, buf, sizeof(buf));sendn(peerfd, &ret, 4);   // 发送块大小sendn(peerfd, buf, ret);  // 发送块数据sent += ret;printf("\r发送进度: %.2f%%", (double)sent * 100 / st.st_size);fflush(stdout);}printf("\n发送完成\n");close(fd);return 0;
}

客户端实现

客户端连接服务器并接收文件:

int main()
{// 创建socket并连接服务器int clientfd = socket(AF_INET, SOCK_STREAM, 0);struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(8080);addr.sin_addr.s_addr = inet_addr("192.168.34.xxx");connect(clientfd, (struct sockaddr *)&addr, sizeof(addr));// 接收文件名char filename[20] = {0};int len = 0;recv(clientfd, &len, 4, 0);recv(clientfd, filename, len, 0);// 接收文件大小off_t filesize = 0;recv(clientfd, &filesize, sizeof(filesize), 0);// 接收文件内容char buf[1000] = {0};int fd = open(filename, O_RDWR | O_CREAT, 0777);while (1){int ret = recv(clientfd, &len, 4, 0);if (ret == 0) break;ret = recv(clientfd, buf, len, 0);write(fd, buf, len);}close(clientfd);close(fd);return 0;
}

编译与运行

编译

项目使用makefile进行编译管理:

# 编译所有目标
all: server client01# 编译服务器
server: server.o transfer.o sendfd.o main.o child.og++ $^ -o $@# 编译客户端
client01: client01.cppg++ $^ -o $@# 清理编译产物
clean:rm -rf *.o server client01

运行

  1. 启动服务器:
./server 192.168.34.xxx 8080 4

参数分别为:IP地址、端口号、子进程数量

  1. 启动客户端:
./client01

总结

本项目通过进程池技术实现了一个高效的并发服务器框架,主要特点有:

  1. 高并发处理:采用预创建的进程池,避免频繁创建销毁进程的开销
  2. 高效通信:使用Unix域套接字实现父子进程间的双向通信
  3. 描述符传递:通过SCM_RIGHTS传递文件描述符,实现优雅的任务分发
  4. I/O多路复用:使用epoll机制监听多个文件描述符,提高I/O效率
  5. 状态管理:通过状态标识维护子进程的工作状态

该框架可作为网络服务器的基础架构,通过修改业务处理逻辑,可以适用于各种网络服务场景。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

wordpress-网站百宝箱插件

含置顶,网页宠物, 哀悼, 禁止复制, 禁止查看源码, 弹幕, WP优化,媒体分类,预加载,定时发布,在线客服, 留言板, 手机客服, 网站背景, 公告, 跑马灯, 水印, 分享, 打赏, 海报图, 广告,数据库管理,图片加载特效。等综合功能插件

Git 钩子:特定操作脚本

Git 钩子 在特定 Git 操作发生时自动触发的脚本&#xff1b; 可以从提交规范、代码质量、自动化流程、分支管理、安全性检查等多个方面进行配置&#xff0c;帮助团队提高开发效率和代码质量&#xff1b; 本地 记录提交检验 commit-msg 修改&#xff1a;\test\.git\hooks\c…

职坐标:互联网行业职业发展路径解析

内容概要 当前&#xff0c;互联网行业正以指数级速度重塑全球产业格局。数据显示&#xff0c;我国互联网市场规模在2019年上半年实现17.9%的同比增速&#xff0c;而随着工业互联网、5G等前沿技术的加速落地&#xff0c;这一增长趋势仍在强化。工信部近期发布的《新型信息基础设…

红数码影视(RED Digital Cinema)存储卡格式化后的恢复方法

红数码影视(RED Digital Cinema)的摄像机可以生成两种RAW级高清视频文件&#xff0c;一种是R3D&#xff0c;一种是MOV。其中MOV属于苹果(apple)公司的QT视频封装结构&#xff0c;使用的视频编码是Apple ProRes;而R3D则是RED公司自创的RAW视频文件&#xff0c;这种文件解码需要使…

Gitee上库常用git命令

Gitee上库常用git命令 1、Fork 项目2、个人仓库修改3、追加提交4、创建PR5、多笔commit合一 1、Fork 项目 2、个人仓库修改 git add . // -s 表示自动添加邮箱签名信息&#xff0c;-m表示其后跟随commit描述 git commit -sm “add transition freeze” git push origin [目标…

阿里开源的免费数据集成工具——DataX

企业里真实的数据流转是什么样子的呢&#xff1f; 左侧描述了一个企业真实的样子&#xff0c;我们总是需要把数据从一个地方搬到另一个地方&#xff0c;最后就是搬来搬去搬成了一张张解不开的网。 右侧则表达了使用DataX为中心实现数据的同步。 什么是DataX DataX是一个异构…

SpringBoot学习笔记(主)

文章目录 SpringBoot概述自动装配&#xff08;部分&#xff09;概述原理简述相关解释源码位置EnableAutoConfigurationAutoConfigurationImportSelector 配置文件yaml语法单双引号列表多行字符串 配置文件的位置和加载顺序配置文件取值运行jar包 Springboot整合springmvc自动管…

python多线程和多进程的区别有哪些

python多线程和多进程的区别有七种&#xff1a; 1、多线程可以共享全局变量&#xff0c;多进程不能。 2、多线程中&#xff0c;所有子线程的进程号相同&#xff1b;多进程中&#xff0c;不同的子进程进程号不同。 3、线程共享内存空间&#xff1b;进程的内存是独立的。 4、同一…

docker 安装部署 canal

1 mysql 安装 1.1 拉取镜像 docker pull mysql:8.4.41.2 创建挂载目录 mkdir -p /user/lzl/tool/docker/mysql/mysql_8.4.4/home/confmkdir -p /user/lzl/tool/docker/mysql/mysql_8.4.4/home/datamkdir -p /user/lzl/tool/docker/mysql/mysql_8.4.4/home/log1.3 编辑配置文…

基于SpringBoot的图书借阅小程序+LW参考示例

系列文章目录 1.基于SSM的洗衣房管理系统原生微信小程序LW参考示例 2.基于SpringBoot的宠物摄影网站管理系统LW参考示例 3.基于SpringBootVue的企业人事管理系统LW参考示例 4.基于SSM的高校实验室管理系统LW参考示例 5.基于SpringBoot的二手数码回收系统原生微信小程序LW参考示…

ElasticSearch快速入门--实现分词搜索

分词题目搜索 使用Elasticsearch实现题目数据的存储和分词搜索&#xff0c;需要将数据库的数据同步到 Elasticsearch。 ElasticSearch入门 ElasticSearch&#xff08;简称ES&#xff09;是一个开源的分布式搜索和数据分析引擎&#xff0c;用Java开发并且是当前最流行的开源的…

debug - 安装.msi时,为所有用户安装程序

文章目录 debug - 安装.msi时&#xff0c;为所有用户安装程序概述笔记试试在目标.msi后面直接加参数的测试 备注备注END debug - 安装.msi时&#xff0c;为所有用户安装程序 概述 为了测试&#xff0c;装了一个test.msi. 安装时&#xff0c;只有安装路径的选择&#xff0c;没…

Skyeye 云智能制造办公系统 VUE 版本 v3.15.14 发布

Skyeye 云智能制造&#xff0c;采用 Springboot winUI 的低代码平台、移动端采用 UNI-APP。包含 30 多个应用模块、50 多种电子流程&#xff0c;CRM、PM、ERP、MES、ADM、EHR、笔记、知识库、项目、门店、商城、财务、多班次考勤、薪资、招聘、云售后、论坛、公告、问卷、报表…

深度学习PyTorch之动态计算图可视化 - 使用 torchviz 生成计算图

序号系列文章1深度学习训练中GPU内存管理2深度学习PyTorch之数据加载DataLoader3深度学习 PyTorch 中 18 种数据增强策略与实现4深度学习pytorch之简单方法自定义9类卷积即插即用5深度学习PyTorch之13种模型精度评估公式及调用方法6深度学习pytorch之4种归一化方法&#xff08;…

ZW3D二次开发_非模板表单_输入框类控件_逐字符回调

ZW3D的非模板表单的控件中有一些输入框类的控件&#xff0c;比如“ZsCc::LineEditBtn”,"ZsCc::LineEditEx"等&#xff0c;按照“ZW3D二次开发_非模板表单_控件_添加回调-CSDN博客”介绍的方法添加函数命令时&#xff0c;发现输入框在用户输入字符时不能动态地触发回…

Mysql--日志(错误日志、二进制日志、查询日志、慢查询日志)

四种日志对比总结 日志类型作用记录内容特点常见用途错误日志记录 MySQL 运行过程中的错误、警告及启动、关闭信息MySQL 系统错误、故障信息、警告等较少占用磁盘空间故障排查、系统监控二进制日志记录所有更改数据库数据的操作及事务执行情况DML、DDL 操作&#xff0c;不记录…

AI对软件工程(software engineering)的影响在哪些方面?

AI对软件工程&#xff08;software engineering&#xff09;的影响是全方位且深远的&#xff0c;它不仅改变了传统开发流程&#xff0c;还重新定义了工程师的角色和软件系统的构建方式。以下是AI影响软件工程的核心维度&#xff1a; 一、开发流程的智能化重构 需求工程革命 • …

ElementPlus 快速入门

目录 前言 为什么要学习 ElementPlus&#xff1f; 正文 步骤 1 创建 一个工程化的vue 项目 ​2 安装 element-Plus :Form 表单 | Element Plus 1 点击 当前界面的指南 2 点击左边菜单栏上的安装&#xff0c;选择包管理器 3 运行该命令 demo(案例1 &#xff09; 步骤 …

stable diffusion本地安装

1. 基本环境准备 安装conda 环境 pytorch基础学习-CSDN博客 创建虚拟环境&#xff1a; conda create -n sd python3.10 一定要指定用3.10&#xff0c;过高的版本会提示错误&#xff1a; 激活启用环境&#xff1a; conda activate sd 设置pip国内镜像源&#xff1a; pip conf…

使用 Go 构建 MCP Server

一个互联网技术玩家&#xff0c;一个爱聊技术的家伙。在工作和学习中不断思考&#xff0c;把这些思考总结出来&#xff0c;并分享&#xff0c;和大家一起交流进步。 一、MCP 介绍 1. 基本介绍 MCP&#xff08;Model Context Protocol&#xff0c;模型上下文协议&#xff09;是…