当前位置: 首页 > news >正文

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

运行图

两个客户端访问服务器端

image-20241212182721902

3.代码解释

1.指定的固定端口号为1234

也可以用argv接受ip和port参数

2.srv_addr.sin_addr.s_addr=htonl(INADDR_ANY);

  • sin_addrstruct 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.父子进程是共享文件描述符表的

  1. 父子进程共享文件描述符表的含义
    • 在 Unix 和 Linux 系统中,当父进程创建子进程时,子进程会继承父进程的文件描述符表。这意味着父子进程可以通过相同的文件描述符来访问同一个文件或 I/O 资源。文件描述符表是一个进程用于管理打开文件或其他 I/O 设备的表格,其中每个文件描述符是一个整数索引,对应着一个打开的文件或设备的相关信息(如文件状态、读写位置等)。
    • 例如,父进程打开了一个文件,得到文件描述符为 3,当创建子进程后,子进程也会有一个文件描述符为 3,并且这个文件描述符在父子进程中都指向同一个打开的文件。这种共享机制使得父子进程可以方便地共享文件资源,比如共同对一个文件进行读写操作。
  2. 父进程close(5)后子进程的情况
    • 当父进程执行close(5)操作后,只是父进程自己释放了文件描述符 5 所对应的资源。子进程的文件描述符表仍然保留文件描述符 5,并且子进程仍然可以使用文件描述符 5 来访问对应的文件。
    • 原因是父子进程的文件描述符表虽然在创建子进程时是共享的,但它们在操作文件描述符时是相互独立的。父进程的close操作不会影响子进程中已经继承的相同文件描述符。
  3. 子进程是否可以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 通过的是非阻塞忙轮询的方式实现的 和阻塞等待的区别就是&#xff0c;阻塞是真的阻塞了&#xff0c;而这个方式是一直在问有没有请求有没有请求 文章目录 多进程并发服务器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参数&#xff0c;Top_P与Top_K&#xff0c;Beamsearch&#xff0c;temperature 都是什么关系以及该如何选择Top_P参数。 文章目录 一、什么是Top_P参数&#xff1f;二、工作原理三、top_p和top_k是什么关系&#xff1f;四、Top_P和BeamSea…...

hive+hadoop架构数仓使用问题记录

使用问题记录 问题1&#xff1a;5条数据的表执行count(*)函数&#xff0c;很慢&#xff0c;43s才出结果&#xff1f; 该数仓的分析计算是基于hadoop的mapreduce分布式计算框架运行的&#xff0c;适用于大量/海量数据&#xff0c;少量数据&#xff0c;还是使用单体数据库快。也…...

前端的 Python 入门指南(三):数据类型对比 - 彻底的一切皆对象实现和包装对象异同

《前端的 Python 入门指南》系列文章&#xff1a; &#xff08;一&#xff09;&#xff1a;常用语法和关键字对比&#xff08;二&#xff09;&#xff1a;函数的定义、参数、作用域对比&#xff08;三&#xff09;&#xff1a;数据类型对比 - 彻底的一切皆对象实现和包装对象异…...

Axios结合Typescript 二次封装完整详细场景使用案例

Axios 是一个基于 promise 的 HTTP 客户端&#xff0c;用于浏览器和 node.js。二次封装 Axios 主要是为了统一管理 HTTP 请求&#xff0c;例如设置统一的请求前缀、头部、超时时间&#xff0c;统一处理请求和响应的格式&#xff0c;以及错误处理等。 以下是一个使用 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) 是一项实时通讯技术&#xff0c;它允许网络应用或者站点&#xff0c;在不借助中间媒介的情况下&#xff0c;建立浏览器之间点对点&#xff08;Peer-to-Peer&#xff09;的连接&#xff0c;实现视频流和&#xff08;或&a…...

element左侧导航栏

由element组件搭建的左侧导航栏 预览: html代码: <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>首页</title><style> /*<!-- 调整页面背景颜色-->*/body{background-colo…...

【金融贷后】贷后运营精细化管理

文章目录 一、贷后专业术语讲解① 什么是贷后&#xff0c;贷后部是干什么的&#xff1f;② 贷后部门常见组织架构&#xff1f;③ 贷后专业术语有哪些&#xff1f; 二、贷后常用作业手段介绍① 贷后产品形态介绍&#xff1f;② 催收常用的方法&#xff1f; 三、贷后策略岗位介绍…...

学习CSS第七天

学习文章目录 一.交集选择器 一.交集选择器 使用多个条件符合的元素&#xff0c;可提高区分的精准度 元素配合类名是使用场景最多的 &#xff08;元素必须是第一位&#xff0c;ID一般不写&#xff09; <!DOCTYPE html> <html lang"zh-CN"> <head>…...

Image Stitching using OpenCV

文章目录 简介图像拼接管道特征检测和提取特征检测特征提取 特征匹配强力匹配FLANN&#xff08;近似最近邻快速库&#xff09;匹配 单应性估计扭曲和混合结论 使用opencv进行图像拼接 原为url: https://medium.com/paulsonpremsingh7/image-stitching-using-opencv-a-step-by-s…...

CentOS7 安装Selenium(使用webdriver_manager自动安装ChromeDriver)

在 CentOS 7 上安装 Selenium 通常涉及几个步骤&#xff0c;包括安装 Python、安装 Selenium 库、安装 WebDriver 以及配置环境。以下是详细的步骤&#xff1a; 1. 安装 Python 和 pip 如果你的系统中还没有安装 Python 和 pip&#xff0c;可以使用以下命令进行安装&#xff…...

鸿蒙手机文件目录

最近在开发鸿蒙&#xff0c;想把文件从电脑上发送到鸿蒙上我的手机APP的根目录&#xff0c;但是试了几次目录都不对&#xff0c;最后终于找到了&#xff0c;在这里记录一下 鸿蒙手机路径: /storage/media/100/local/files/Docs 将文件从电脑发送到手机&#xff1a;hdc file s…...

泷羽Sec学习笔记-Bp中ip伪造、爬虫审计

ip伪造与爬虫审计 ip伪造 下载插件&#xff1a;burpFakeIP 地址&#xff1a;GitHub - TheKingOfDuck/burpFakeIP: 服务端配置错误情况下用于伪造ip地址进行测试的Burp Suite插件 python版需要配置jython&#xff1a;下载地址&#xff1a;Maven Central: org.python:jython-…...

电子电工一课一得

首语 在现代社会中&#xff0c;电子电工技术已经渗透到我们生活的方方面面&#xff0c;从家用电器到工业自动化&#xff0c;从通信设备到智能系统&#xff0c;无一不依赖于电子电工技术。因此&#xff0c;掌握电子电工的基础知识&#xff0c;不仅对理工科学生至关重要&#xf…...

Cesium 限制相机倾斜角(pitch)滑动范围

1.效果 2.思路 在项目开发的时候&#xff0c;有一个需求是限制相机倾斜角&#xff0c;也就是鼠标中键调整视图俯角时&#xff0c;不能过大&#xff0c;一般 pitch 角度范围在 0 至 -90之间&#xff0c;-90刚好为正俯视。 在网上查阅了很多资料&#xff0c;发现并没有一个合适的…...

配置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.进程创建 我们在之前的文章中介绍过进程创建的方法&#xff0c;可以通过系统调用接口fork来创建新的进程。 fork在创建完新的子进程之后&#xff0c;返回值是一个pid&#xff0c;对于父进程返回子进程的pid&#xff0c;对于子进程返回0。fork函数后父子进程共享代码&#xff…...

【HarmonyOS】鸿蒙应用实现手机摇一摇功能

【HarmonyOS】鸿蒙应用实现手机摇一摇功能 一、前言 手机摇一摇功能&#xff0c;是通过获取手机设备&#xff0c;加速度传感器接口&#xff0c;获取其中的数值&#xff0c;进行逻辑判断实现的功能。 在鸿蒙中手机设备传感器ohos.sensor (传感器)的系统API监听有以下&#xf…...

【网络】每天掌握一个Linux命令 - iftop

在Linux系统中&#xff0c;iftop是网络管理的得力助手&#xff0c;能实时监控网络流量、连接情况等&#xff0c;帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】

微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来&#xff0c;Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...

java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别

UnsatisfiedLinkError 在对接硬件设备中&#xff0c;我们会遇到使用 java 调用 dll文件 的情况&#xff0c;此时大概率出现UnsatisfiedLinkError链接错误&#xff0c;原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用&#xff0c;结果 dll 未实现 JNI 协…...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增&#xff1a;通道注意力模块&#xff08;SE模块&#xff09; class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

376. Wiggle Subsequence

376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

uniapp微信小程序视频实时流+pc端预览方案

方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度​WebSocket图片帧​定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐​RTMP推流​TRTC/即构SDK推流❌ 付费方案 &#xff08;部分有免费额度&#x…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

Typeerror: cannot read properties of undefined (reading ‘XXX‘)

最近需要在离线机器上运行软件&#xff0c;所以得把软件用docker打包起来&#xff0c;大部分功能都没问题&#xff0c;出了一个奇怪的事情。同样的代码&#xff0c;在本机上用vscode可以运行起来&#xff0c;但是打包之后在docker里出现了问题。使用的是dialog组件&#xff0c;…...