多进程并发服务器
文章目录
- 思路
- 问题
- 多进程并发回环服务器代码
- 客户端代码
思路
每当一个客户端连接服务器后,创建一个子进程负责与该客户端通信,客户端断开连接之后,服务器回收子进程资源。
问题
问题1:父进程阻塞在等待连接(
accept())处,不能在父进程回收资源,可以使用信号SIGCHLD进行软中断回调处理,当子进程结束后会产生SIGCHLD信号,信号触发回调函数,进程子进程资源回收,父进程阻塞在accept()函数时遇到软中断就会产生EINTR错误信号,这就需要处理accept函数返回值为-1时的错误,判断错误号errno,若errno == EINTR则继续等待客户端连接进入accept阻塞。
问题2:由于多个进程同时退出时也仅有一个
SIGCHLD信号,所以在有SIGCHLD信号时,回调函数内就要循环执行释放子进程资源,直到子进程资源释放完成。
信号的注册,以及回调函数的编写:
//子进程回收回调函数
void recvChild(int arg)
{while(1){int ret = waitpid(-1, NULL, WNOHANG);if(ret > 0){printf("recv child, the num is:%d\n", ret);}else if(ret == 0){//还有子进程}else if(ret == -1){//没有子进程了break;}}
}//注册信号,解决子进程的回收问题struct sigaction act;act.sa_flags = 0;sigemptyset(&act.sa_mask);act.sa_handler = recvChild;sigaction(SIGCHLD, &act, NULL);
问题3:在使用客户端发送数据的时候,是先使用
write发送数据,然后通过read读取数据,该读取是阻塞的,所以一开始没有数据时是一直阻塞的,回环服务器接收到数据回传给客户端,这样客户端和服务器同时进行read时,就会出现都阻塞的状态。
可以设置客户端先发送,再读取,客户端发送后,数据经过服务器回传,客户端收到数据后,再进行下一次发送,若有一次数据丢失则无法进行数据发送,有一直阻塞在接收的风险。
也可以在客户端设置两个进程,一个发送进程,一个接收进程,这样就可以解决。
问题4:接收数据中没有结束符’\0’,在`printf %s时,会导致数据错误(数据先长后短,打印的会包含上次数据),注意结束符的位置,strlen计算到结束符之前。
通过在接收的字符串后补上结束符处理
或者接收数据前对接收数组进行清空处理
********////接收数据没有字符结束符,无法判断数据结束,//使用printf%s出现问题:可以将末尾增加字符结束符/0,也可以使用数据初始化(浪费资源)
//memset(recv, 0, 1024);
int len = read(cfd, recv, 1024);
recv[len] = 0;
多进程并发回环服务器代码
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <wait.h>
#include <errno.h>void recvChild(int arg)
{while(1){int ret = waitpid(-1, NULL, WNOHANG);if(ret > 0){printf("recv child, the num is:%d\n", ret);}else if(ret == 0){//还有子进程}else if(ret == -1){//没有子进程了break;}}
}int main()
{//注册信号,解决子进程的回收问题struct sigaction act;act.sa_flags = 0;sigemptyset(&act.sa_mask);act.sa_handler = recvChild;sigaction(SIGCHLD, &act, NULL);//socketint lfd = socket(PF_INET, SOCK_STREAM, 0);if(lfd == -1){perror("socket");exit(-1);}//bindstruct sockaddr_in saddr;saddr.sin_family = AF_INET;inet_pton(AF_INET, "192.168.1.108", &saddr.sin_addr.s_addr);//saddr.sin_addr.s_addr = INADDR_ANY;saddr.sin_port = htons(9999);int ret = bind(lfd, (struct sockaddr *)&saddr, sizeof(saddr));if(ret == -1){perror("bind");exit(-1);}//listenret = listen(lfd, 2);if(ret == -1){perror("listen");exit(-1);}int prosess_num = 0;while(1){//acceptstruct sockaddr_in caddr;socklen_t len = sizeof(caddr);int cfd = accept(lfd, (struct sockaddr *)&caddr, &len);if(cfd == -1){if(errno == EINTR) continue;perror("accept");exit(-1);}//childprosess_num++;pid_t fd = fork();if(fd == -1){perror("fork");exit(-1);}if(fd == 0){char cip[16];printf("the process %d link success!\n", prosess_num);inet_ntop(AF_INET, &caddr.sin_addr, cip, sizeof(cip));printf("client IP:%s, Port:%d\n\n", cip, ntohs(caddr.sin_port));char recv[1025];while(1){********//
//接收数据没有字符结束符,无法判断数据结束,
//使用printf%s出现问题:可以将末尾增加字符结束符/0,也可以使用数据初始化(浪费资源)//memset(recv, 0, 1024);int len = read(cfd, recv, 1024);recv[len] = 0;if(len == -1){perror("read");exit(-1);}else if(len > 0){if(strcmp(recv, "break\r\n") == 0) break;write(cfd, recv, len+1);printf("IP:%s Port:%d: %s", cip, ntohs(caddr.sin_port), recv);}else{printf("client is closed...\n");break;}}printf("the process %d, IP:%s, port:%d, will close!\n", prosess_num, cip, ntohs(caddr.sin_port));close(cfd);exit(0);}}close(lfd); return 0;
}
客户端代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string.h>
#include <fcntl.h>int main()
{int lfd = socket(PF_INET, SOCK_STREAM, 0);if(lfd == -1){perror("socket");exit(-1);}struct sockaddr_in saddr;saddr.sin_family = AF_INET;int len = sizeof(saddr);inet_pton(AF_INET, "192.168.1.108", &saddr.sin_addr.s_addr);saddr.sin_port = htons(9999);int ret = connect(lfd, (struct sockaddr *)&saddr, sizeof(saddr));if(ret == -1){perror("connect");exit(-1);}printf("client link success!\n");//由于读操作会阻塞,客户端需要先发送数据,若先读取数据,一个进程就会阻塞住,一个进程就要先发数据,如果一次数据没有接收到,则会阻塞住。//可以采用两个进程,发、收互不影响pid_t pid = fork();if(pid==0){char rbuf[1024];while(1){//memset(rbuf, 0, 1024);int lent = read(lfd, rbuf, 1024);if(lent > 0){printf("send: %s", rbuf);}else if(lent == -1) perror("read");}}else if(pid > 0){int i = 0;char sbuf[1024];while(1){ i++;if(i > 255) i = 0;sprintf(sbuf, "the num is %d\n", i);write(lfd, sbuf,strlen(sbuf));sleep(1);}}close(lfd);return 0;
}
相关文章:
多进程并发服务器
文章目录 思路问题多进程并发回环服务器代码客户端代码 思路 每当一个客户端连接服务器后,创建一个子进程负责与该客户端通信,客户端断开连接之后,服务器回收子进程资源。 问题 问题1:父进程阻塞在等待连接(accept())处…...
2021秋招总结
2021 秋招总结 作为星球第一批准备秋招的人,经过这几个月的面试之后,感觉也算是有一些小小的经验了吧,就做一个简单的记录,希望能够为星球中准备秋招的伙伴们提供一些参考吧~ 序 4月初加入星球,到9月底,一…...
Linux6.34 Kubernetes yaml文件详解
文章目录 计算机系统5G云计算第三章 LINUX Kubernetes yaml文件详解一、yaml文件概述1.查看 api 资源版本标签2.写一个yaml文件demo 计算机系统 5G云计算 第三章 LINUX Kubernetes yaml文件详解 一、yaml文件概述 Kubernetes 支持 YAML 和 JSON 格式管理资源对象 JSON 格式…...
防火墙笔记
什么是防火墙 在计算机网络中是指设置在可信任的内部网络和不可信任的外部网络之间的屏障,通过强化边界控制保障内容安全,同时不妨碍内部对外部的访问。 20世纪80年代,最早的防火墙几乎与路由器同时出现,第一代防火墙主要基于包过…...
使用代码下载开源的大模型文件示例以及中文微调llama资源汇总:
一、下载示例 from huggingface_hub import snapshot_downloadrepo_id "THUDM/chatglm2-6b" local_dir ./chatglm2-6b/ cache_dir local_dir "/cache" while True:try:snapshot_download(cache_dircache_dir,local_dirlocal_dir,repo_idrepo_id,loca…...
Wav2vec2 论文阅读看到的一些问题
Wav2vec2 论文阅读看到的一些问题 这里只是简单的思考一下论文的一些问题,不是论文解读。 Q1. 为什么wav2vec依旧需要Transformer来做推理,而不直接使用VQ生成的内容? A1. Transformer在更长的序列上有更好的编码效果,例如论文也写…...
爬虫学习记录(持续更新)
一、问题记录 1.使用webdriver报错AttributeError: str object has no attribute capabilities 解决:目前使用的selenium版本是4.11.2,可以不必设置driver.exe的路径,selenium可以自己处理浏览器和驱动程序,因此,使用…...
libevent源码学习1---创建event
libevent源码学习1—创建event Libevent是一个用于开发可扩展性网络服务器的基于事件驱动(event-driven)模型的非阻塞网络库。安装请参考ubuntu下载安装libevent event_base 使用 libevent 函数之前需要分配一个或者多个 event_base 结构体。每个 event_base 结构体持有一个…...
Python类的设计
Python类的设计 # 定义一个闹钟类 class Clock:__cureen_keyNone # 私有成员不能改变和使用def __init__(self, id, price): # 类对象是立即自动执行self.id idself.price pricedef ring(self):import winsound # 内置声音方法winsound.Beep(2000,3000)clock1 Clock(…...
微信小程序的项目解构
视频链接 黑马程序员前端微信小程序开发教程,微信小程序从基础到发布全流程_企业级商城实战(含uni-app项目多端部署)_哔哩哔哩_bilibili 接口文档 https://www.escook.cn/docs-uni-shop/mds/1.start.html 1:微信小程序宿主环境 1:常见的宿…...
【Archaius技术专题】「Netflix原生态」动态化配置服务之微服务配置组件变色龙
前提介绍 如果要设计开发一套微服务基础架构,参数化配置是一个非常重要的点,而Netflix也开源了一个叫变色龙Archaius的配置中心客户端,而且Archaius可以说是比其他客户端具备更多生产级特性,也更灵活。*在NetflixOSS微服务技术栈…...
python条件分支和循环语句
python中没有{}的写法,一般时通过缩进的方式来确定分支和循环需要执行的代码块。 if 需要判断的条件表达式:条件成立时的动作 elif 需要判断的条件表达式:条件成立时的动作 else:动作for 变量 in 迭代对象:动作 示例: while 退出条件:动作...
工具推荐:Wireshark网络协议分析工具(对比tcpdump)
文章首发地址 Wireshark是一款开源的网络协议分析工具,可以捕获网络数据包并对其进行详细的分析和解释。下面是Wireshark的详细介绍: Wireshark 工作原理 Wireshark通过捕获网络接口上的数据包,将其转换为可读的格式,并在界面…...
[OnWork.Tools]系列 04-快捷启动
简介 主要功能是将常用的软件拖动到软件中,实现快速点击启动,结合软件设置中的设置的快捷键,可以快速呼出对应的面板,使用快捷键快速启动应用 拖拽内容 拖拽快捷方式到面板,双击快速打开 拖拽文件方式到面板,双击快速打开 拖拽文件夹到面板双击快速打开 拖拽项目调整顺序 右…...
如何将项目挂后台运行?【nohup和tmux】
挂后台运行,防止霸屏。 线上的程序不会将日志输出到控制台,而是输出到日志文件,方便运维查阅信息。 一.nohup--挂后台运行的命令 //nohup--英文全称no hang up,可以后台运行指定命令 //hello.log是指将日志输出到hello.log文件 …...
什么是进程、线程、协程
什么是进程? 我们都知道计算机的核心是CPU,它承担了所有的计算任务;而操作系统是计算机的管理者,它负责任务的调度、资源的分配和管理,统领整个计算机硬件;应用程序则是具有某种功能的程序,程序…...
Python爬虫——selenium_访问元素信息
from selenium import webdriver# 创建浏览器对象 path files/chromedriver.exe browser webdriver.Chrome(path)# 访问地址 url https://www.baidu.com browser.get(url)input browser.find_element_by_id(su)获取元素属性 .get_attribute(class)print(input.get_attribu…...
Linux 文件基本属性
Linux 文件基本属性 Linux 系统是一种典型的多用户系统,不同的用户处于不同的地位,拥有不同的权限。 为了保护系统的安全性,Linux 系统对不同的用户访问同一文件(包括目录文件)的权限做了不同的规定。 在 Linux 中我…...
CSS 盒模型是什么?它包含哪些属性?标准盒模型/怪异盒模型
聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 盒模型⭐ 标准盒模型⭐ 怪异盒模型⭐ 写在最后 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅!这个专栏是为那些对Web开发感…...
VB+SQL光盘信息管理系统设计与实现
摘 要 我的毕业设计课题为“光盘管理系统”,该系统完成光盘相关信息的输入、保存和维护、是按照方便用户、容易操作、确保数据一致完整的原则进行设计。这次毕业设计的开发工具是Visual Basic 6.0,操作平台是Windows2000 Professional中文版,选用的数据库后台是SQL server2…...
wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...
大数据学习栈记——Neo4j的安装与使用
本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...
用docker来安装部署freeswitch记录
今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...
RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文全面剖析RNN核心原理,深入讲解梯度消失/爆炸问题,并通过LSTM/GRU结构实现解决方案,提供时间序列预测和文本生成…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...
Web中间件--tomcat学习
Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机,它可以执行Java字节码。Java虚拟机是Java平台的一部分,Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...
flow_controllers
关键点: 流控制器类型: 同步(Sync):发布操作会阻塞,直到数据被确认发送。异步(Async):发布操作非阻塞,数据发送由后台线程处理。纯同步(PureSync…...
stm32进入Infinite_Loop原因(因为有系统中断函数未自定义实现)
这是系统中断服务程序的默认处理汇编函数,如果我们没有定义实现某个中断函数,那么当stm32产生了该中断时,就会默认跑这里来了,所以我们打开了什么中断,一定要记得实现对应的系统中断函数,否则会进来一直循环…...
基于Python的气象数据分析及可视化研究
目录 一.🦁前言二.🦁开源代码与组件使用情况说明三.🦁核心功能1. ✅算法设计2. ✅PyEcharts库3. ✅Flask框架4. ✅爬虫5. ✅部署项目 四.🦁演示效果1. 管理员模块1.1 用户管理 2. 用户模块2.1 登录系统2.2 查看实时数据2.3 查看天…...
