linux网络编程 | c | 多进程并发服务器实现
多进程并发服务器
基于该视频完成
11-多进程并发服务器思路分析_哔哩哔哩_bilibili
通过的是非阻塞忙轮询的方式实现的
和阻塞等待的区别就是,阻塞是真的阻塞了,而这个方式是一直在问有没有请求有没有请求
文章目录
- 多进程并发服务器
- 1.核心思路&功能
- 2.代码实现
- warp.h
- warp.c
- multi_process_concurrency_sever.c
- 运行图
- 3.代码解释
1.核心思路&功能
实现一个服务器可以连接多个客户端,每当accept函数等待到客户端进行连接时 就创建一个子进程;
核心思路:让accept循环阻塞等待客户端,每当有客户端连接时就fork子进程,让子进程去和客户端进行通信,父进程用于监听并使用信号捕捉回收子进程;(子进程关闭用于监听的套接字lfd,父进程关闭用于通信的cfd)
**功能:**客户端输入小写字符串,服务器转成大写返回给客户端
2.代码实现
warp.h
#ifndef __WRAP_H_
#define __WRAP_H_
#include<sys/epoll.h>
//#include<event2/event.h>
#include<sys/select.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<errno.h>
#include<string.h>
#include<dirent.h>
#include<sys/stat.h>
#include<wait.h>
#include<sys/mman.h>
#include<signal.h>
#include<pthread.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<ctype.h>
#include<strings.h>
#include<netinet/ip.h>
#define SRV_PORT 1234void perr_exit(const char *s);
int Accept(int fd,struct sockaddr *sa,socklen_t * salenptr);
int Bind(int fd, const struct sockaddr *sa, socklen_t salen);
int Connect(int fd, const struct sockaddr *sa, socklen_t addrlen);
int Listen(int fd, int backlog);
int Socket(int family, int type, int protocol);
size_t Read(int fd, void *ptr, size_t nbytes);
ssize_t Write(int fd,const void *ptr,size_t nbytes);
int Close(int fd);
ssize_t Readn(int fd, void *vptr, size_t n);
ssize_t Writen(int fd, const void *vptr, size_t n);
ssize_t my_read(int fd, char *ptr);
ssize_t Readline(int fd, void *vptr, size_t maxlen);#endif
warp.c
#include"warp.h"void perr_exit(const char *s)
{perror(s);exit(1);
}int Accept(int fd,struct sockaddr *sa,socklen_t * salenptr)
{int n;
again:if((n=accept(fd,sa,salenptr))<0){if((errno==ECONNABORTED)||(errno==EINTR))goto again;elseperr_exit("accept error");}return n;
}int Bind(int fd, const struct sockaddr *sa, socklen_t salen)
{int n;if((n=bind(fd,sa,salen))<0)perr_exit("bind error");return n;
}int Connect(int fd, const struct sockaddr *sa, socklen_t addrlen)
{int n;n=connect(fd,sa,addrlen);if(n<0){perr_exit("connect error");}return n;
}int Listen(int fd, int backlog)
{int n;if((n=listen(fd,backlog))<0)perr_exit("listen error");return n;
}int Socket(int family, int type, int protocol)
{int n;if((n=socket(family,type,protocol))<0)perr_exit("socket error");return n;
}size_t Read(int fd, void *ptr, size_t nbytes)
{ssize_t n;
again:if((n=read(fd,ptr,nbytes))==-1){if(errno==EINTR)goto again;elsereturn -1;}return n;
}ssize_t Write(int fd,const void *ptr,size_t nbytes)
{ssize_t n;
again:if((n=write(fd,ptr,nbytes))==-1){if(errno==EINTR)goto again;elsereturn -1;}return 0;
}int Close(int fd)
{int n;if((n=close(fd))==-1)perr_exit("close error");return n;
}ssize_t Readn(int fd, void *vptr, size_t n)
{size_t nleft;ssize_t nread;char *ptr;ptr=vptr;nleft=n;while(nleft>0){if((nread=read(fd,ptr,nleft))<0){if(errno==EINTR)nread=0;elsereturn -1;}else if(nread==0)break;}
}
ssize_t Writen(int fd, const void *vptr, size_t n)
{size_t nleft;ssize_t nwritten;char *ptr;ptr=(char *)vptr;nleft=n;while(nleft>0){if((nwritten=write(fd,ptr,nleft))<=0){if(nwritten<0&&errno==EINTR)nwritten=0;elsereturn -1;}nleft-=nwritten;ptr+=nwritten;}return n;
}ssize_t my_read(int fd, char *ptr)
{static int read_cnt;static char *read_ptr;static char read_buf[100];if(read_cnt<=0){
again:if((read_cnt=read(fd,read_buf,sizeof(read_buf)))<0){if(errno==EINTR)goto again;return -1;}else if(read_cnt==0)return 0;read_ptr=read_buf;}read_cnt--;*ptr=*read_ptr++;return 1;
}ssize_t Readline(int fd, void *vptr, size_t maxlen)
{ssize_t n,rc;char c,*ptr;ptr=vptr;for(n=1;n<maxlen;n++){if((rc=my_read(fd,&c))==1){*ptr++=c;if(c=='\n')break;}else if(rc==0){*ptr=0;return n-1;}else return -1;}*ptr=0;return n;
}
multi_process_concurrency_sever.c
#include"warp.h"//回调函数,父进程用来完成子进程回收的
void catch_child(int signum)
{while((waitpid(0,NULL,WNOHANG))>0);return ;
}int main(int argc,char *argv[])
{int lfd,cfd;pid_t pid;int ret;char buf[1024];struct sockaddr_in srv_addr,clt_addr;socklen_t clt_addr_len;//地址结构清0bzero(&srv_addr,sizeof(srv_addr));srv_addr.sin_family=AF_INET;srv_addr.sin_port=htons(SRV_PORT);srv_addr.sin_addr.s_addr=htonl(INADDR_ANY);lfd=Socket(AF_INET,SOCK_STREAM,0);Bind(lfd,(struct sockaddr*)&srv_addr,sizeof(srv_addr));Listen(lfd,128);clt_addr_len=sizeof(clt_addr);int i;while(1){cfd=Accept(lfd,(struct sockaddr *)&clt_addr,&clt_addr_len);pid=fork();if(pid<0){perr_exit("fork error");}else if(pid==0)//子进程{//关闭用不到的socketclose(lfd);for(;;){ret=Read(cfd,buf,sizeof(buf));if(ret==0){Close(cfd);exit(1);}//逻辑处理部分for(i=0;i<ret;i++)buf[i]=toupper(buf[i]);write(cfd,buf,ret);write(STDOUT_FILENO,buf,ret);}}else//父进程{//注册信号struct sigaction act;act.sa_handler=catch_child;sigemptyset(&act.sa_mask);act.sa_flags=0;ret=sigaction(SIGCHLD,&act,NULL);if(ret!=0){perr_exit("sigaction error");}Close(cfd);continue;}}return 0;
}
gcc warp.c multi_process_concurrency_sever.c -o multi_process_concurrency_sever
运行图
两个客户端访问服务器端

3.代码解释
1.指定的固定端口号为1234
也可以用argv接受ip和port参数
2.srv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
sin_addr是struct sockaddr_in结构体中的一个嵌套结构体,其成员s_addr用于存放 IP 地址信息(以 32 位整数形式表示)。htonl函数和htons类似,不过它是将主机字节序的 32 位整数(通常用于 IP 地址)转换为网络字节序。INADDR_ANY是一个特殊的常量,它表示服务器端套接字可以绑定到本机的任意可用 IP 地址上,通过这行代码,将转换为网络字节序后的INADDR_ANY值赋给了srv_addr结构体的sin_addr.s_addr成员,使得服务器能够监听来自本机所有网络接口上对应端口的连接请求。
3.需要用到的调用都需要错误处理,封装到warp.c后进行使用
4.父子进程是共享文件描述符表的
- 父子进程共享文件描述符表的含义
- 在 Unix 和 Linux 系统中,当父进程创建子进程时,子进程会继承父进程的文件描述符表。这意味着父子进程可以通过相同的文件描述符来访问同一个文件或 I/O 资源。文件描述符表是一个进程用于管理打开文件或其他 I/O 设备的表格,其中每个文件描述符是一个整数索引,对应着一个打开的文件或设备的相关信息(如文件状态、读写位置等)。
- 例如,父进程打开了一个文件,得到文件描述符为 3,当创建子进程后,子进程也会有一个文件描述符为 3,并且这个文件描述符在父子进程中都指向同一个打开的文件。这种共享机制使得父子进程可以方便地共享文件资源,比如共同对一个文件进行读写操作。
- 父进程
close(5)后子进程的情况- 当父进程执行
close(5)操作后,只是父进程自己释放了文件描述符 5 所对应的资源。子进程的文件描述符表仍然保留文件描述符 5,并且子进程仍然可以使用文件描述符 5 来访问对应的文件。 - 原因是父子进程的文件描述符表虽然在创建子进程时是共享的,但它们在操作文件描述符时是相互独立的。父进程的
close操作不会影响子进程中已经继承的相同文件描述符。
- 当父进程执行
- 子进程是否可以
close(5)以及继续访问文件描述符 5 对应的文件- 子进程可以执行
close(5)操作。当子进程执行close(5)后,它自己释放了文件描述符 5 对应的资源,之后就不能再通过文件描述符 5 来访问原来对应的文件了。 - 在没有执行
close(5)之前,子进程可以继续访问文件描述符 5 对应的文件。它可以进行正常的读写操作(前提是该文件是以合适的模式打开的,如可读可写模式),并且文件的读写位置等状态是在父子进程间共享的。例如,如果父进程已经读取了文件的一部分内容,子进程通过相同的文件描述符 5 继续读取文件时,会从父进程读取后的位置开始读取。
- 子进程可以执行
5.子进程做的事情:
close(lfd)关闭监听套接字
read()
逻辑处理:小写转大写
write()
6.父进程做的事情:子进程的回收
close(cfd)
注册信号捕捉函数
在回调函数中,完成子进程的回收
相关文章:
linux网络编程 | c | 多进程并发服务器实现
多进程并发服务器 基于该视频完成 11-多进程并发服务器思路分析_哔哩哔哩_bilibili 通过的是非阻塞忙轮询的方式实现的 和阻塞等待的区别就是,阻塞是真的阻塞了,而这个方式是一直在问有没有请求有没有请求 文章目录 多进程并发服务器1.核心思路&…...
Vins_Fusion_gpu中source setup.bash
文章目录 source setup.bashsetup.bashsetup.sh脚本的主要功能脚本的详细解释1. **初始化和检查**2. **检测操作系统**3. **设置环境变量**4. **记住 shell 类型**5. **调用 Python 脚本生成环境变量**6. **加载环境钩子**7. **清理** 总结 _setup_util.py_setup_util.py 的完整…...
怎么理解大模型推理时的Top_P参数?
本篇博客介绍一下大模型推理时的Top_P参数,Top_P与Top_K,Beamsearch,temperature 都是什么关系以及该如何选择Top_P参数。 文章目录 一、什么是Top_P参数?二、工作原理三、top_p和top_k是什么关系?四、Top_P和BeamSea…...
hive+hadoop架构数仓使用问题记录
使用问题记录 问题1:5条数据的表执行count(*)函数,很慢,43s才出结果? 该数仓的分析计算是基于hadoop的mapreduce分布式计算框架运行的,适用于大量/海量数据,少量数据,还是使用单体数据库快。也…...
前端的 Python 入门指南(三):数据类型对比 - 彻底的一切皆对象实现和包装对象异同
《前端的 Python 入门指南》系列文章: (一):常用语法和关键字对比(二):函数的定义、参数、作用域对比(三):数据类型对比 - 彻底的一切皆对象实现和包装对象异…...
Axios结合Typescript 二次封装完整详细场景使用案例
Axios 是一个基于 promise 的 HTTP 客户端,用于浏览器和 node.js。二次封装 Axios 主要是为了统一管理 HTTP 请求,例如设置统一的请求前缀、头部、超时时间,统一处理请求和响应的格式,以及错误处理等。 以下是一个使用 TypeScrip…...
基于Kubesphere实现微服务的CI/CD——部署微服务项目(三)
目录 一、kubesphere安装 1、安装本地持久存储 1.1、default-storage-class.yaml 1.2、 openebs-operator.yaml 1.3、安装 Default StorageClass 2、安装kubesphere 2.1、安装Helm 2.2、安装kubesphere 二、配置kubesphere 1、安装插件 2、创建devops项目 3、配置…...
【使用webrtc-streamer解析rtsp视频流】
webrtc-streamer WebRTC (Web Real-Time Communications) 是一项实时通讯技术,它允许网络应用或者站点,在不借助中间媒介的情况下,建立浏览器之间点对点(Peer-to-Peer)的连接,实现视频流和(或&a…...
element左侧导航栏
由element组件搭建的左侧导航栏 预览: html代码: <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>首页</title><style> /*<!-- 调整页面背景颜色-->*/body{background-colo…...
【金融贷后】贷后运营精细化管理
文章目录 一、贷后专业术语讲解① 什么是贷后,贷后部是干什么的?② 贷后部门常见组织架构?③ 贷后专业术语有哪些? 二、贷后常用作业手段介绍① 贷后产品形态介绍?② 催收常用的方法? 三、贷后策略岗位介绍…...
学习CSS第七天
学习文章目录 一.交集选择器 一.交集选择器 使用多个条件符合的元素,可提高区分的精准度 元素配合类名是使用场景最多的 (元素必须是第一位,ID一般不写) <!DOCTYPE html> <html lang"zh-CN"> <head>…...
Image Stitching using OpenCV
文章目录 简介图像拼接管道特征检测和提取特征检测特征提取 特征匹配强力匹配FLANN(近似最近邻快速库)匹配 单应性估计扭曲和混合结论 使用opencv进行图像拼接 原为url: https://medium.com/paulsonpremsingh7/image-stitching-using-opencv-a-step-by-s…...
CentOS7 安装Selenium(使用webdriver_manager自动安装ChromeDriver)
在 CentOS 7 上安装 Selenium 通常涉及几个步骤,包括安装 Python、安装 Selenium 库、安装 WebDriver 以及配置环境。以下是详细的步骤: 1. 安装 Python 和 pip 如果你的系统中还没有安装 Python 和 pip,可以使用以下命令进行安装ÿ…...
鸿蒙手机文件目录
最近在开发鸿蒙,想把文件从电脑上发送到鸿蒙上我的手机APP的根目录,但是试了几次目录都不对,最后终于找到了,在这里记录一下 鸿蒙手机路径: /storage/media/100/local/files/Docs 将文件从电脑发送到手机:hdc file s…...
泷羽Sec学习笔记-Bp中ip伪造、爬虫审计
ip伪造与爬虫审计 ip伪造 下载插件:burpFakeIP 地址:GitHub - TheKingOfDuck/burpFakeIP: 服务端配置错误情况下用于伪造ip地址进行测试的Burp Suite插件 python版需要配置jython:下载地址:Maven Central: org.python:jython-…...
电子电工一课一得
首语 在现代社会中,电子电工技术已经渗透到我们生活的方方面面,从家用电器到工业自动化,从通信设备到智能系统,无一不依赖于电子电工技术。因此,掌握电子电工的基础知识,不仅对理工科学生至关重要…...
Cesium 限制相机倾斜角(pitch)滑动范围
1.效果 2.思路 在项目开发的时候,有一个需求是限制相机倾斜角,也就是鼠标中键调整视图俯角时,不能过大,一般 pitch 角度范围在 0 至 -90之间,-90刚好为正俯视。 在网上查阅了很多资料,发现并没有一个合适的…...
配置ssh-key连接github
GitHub 通过在 2022 年 3 月 15 日删除旧的、不安全的密钥类型来提高安全性。 具体内容参考如下链接 https://docs.github.com/zh/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent mac配置 ssh-keygen -t ed25519 -C …...
Linux——进程控制模拟shell
1.进程创建 我们在之前的文章中介绍过进程创建的方法,可以通过系统调用接口fork来创建新的进程。 fork在创建完新的子进程之后,返回值是一个pid,对于父进程返回子进程的pid,对于子进程返回0。fork函数后父子进程共享代码ÿ…...
【HarmonyOS】鸿蒙应用实现手机摇一摇功能
【HarmonyOS】鸿蒙应用实现手机摇一摇功能 一、前言 手机摇一摇功能,是通过获取手机设备,加速度传感器接口,获取其中的数值,进行逻辑判断实现的功能。 在鸿蒙中手机设备传感器ohos.sensor (传感器)的系统API监听有以下…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...
C/C++ 中附加包含目录、附加库目录与附加依赖项详解
在 C/C 编程的编译和链接过程中,附加包含目录、附加库目录和附加依赖项是三个至关重要的设置,它们相互配合,确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中,这些概念容易让人混淆,但深入理解它们的作用和联…...
