Linux 多进程解决客户端与服务器端通信
写一个服务器端用多进程处理并发,使两个以上的客户端可以同时连接服务器端得到响应。每当接受一个新的连接就fork产生一个子进程,让子进程去处理这个连接,父进程只用来接受连接。
与多线程相比的不同点:多线程如果其中一个线程操作不当,产生了一个信号,会导致整个进程都终止。对于多进程来讲,是产生的子进程去处理客户端的连接,如果子进程终止了,不会影响到其他进程。创建线程的开销比产生新的子进程的开销要小,多线程可以共享整个进程的资源。
服务器端代码ser.c:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<pthread.h>
#include<signal.h>int socket_init();//封装一个套接字,套接字的声明
void do_run(int c)//子进程中处理客户端的方法的实现
{while(1){char buff[128]={0};int num=recv(c,buff,127,0);//相当于readif(num<=0){break;}printf("子进程接收到的信息:%s\n",buff);send(c,"ok",2,0);//相当于write}
}int main()
{int sockfd=socket_init();//调用封装好的套接字方法,创建套接字if(sockfd==-1){printf("创建失败\n");exit(1);}while(1){struct sockaddr_in caddr;//定义客户端的套接字地址int len = sizeof(caddr);//4.接收客户端连接int c=accept(sockfd,(struct sockaddr*)&caddr,&len);if(c<0)//失败{continue;}printf("c=%d\n",c);//5.产生一个子进程来处理客户端的连接,子进程会复制父进程打开的所有文件,上面接收的客户端的连接c也算是文件描述符,这个c也会被复制到子进程中pid_t pid=fork();if(pid==-1) {printf("子进程产生失败\n"); close(c);//关闭c这个连接continue;//重新等待新的连接}else if(pid==0)//子进程产生成功{close(sockfd);//因为子进程不用sockfddo_run(c);//处理客户端,传入的参数是c这个描述符close(c);//子进程在退出之前关闭cprintf("子进程退出,pid=%d\n",getpid());exit(0);//处理完所连接的客户端,子进程必须要退出}else {close(c);//父进程关闭c连接,对子进程没有影响,因为在fork之后,描述符的引用计数加1,这时候父进程关闭,子进程也关闭,最终才能认为c被关闭//如果父进程不关闭c连接,c的值会一直增长}}exit(0);
}int socket_init()//套接字的具体实现
{int sockfd=socket(AF_INET,SOCK_STREAM,0);//1.创建套接字if(sockfd==-1){printf("创建失败\n");return -1;}struct sockaddr_in saddr;//定义服务器端的套接字地址memset(&saddr,0,sizeof(saddr));//清空saddr.sin_family=AF_INET;saddr.sin_port=htons(6000);saddr.sin_addr.s_addr=inet_addr("127.0.0.1");//2.绑定,指定套接字的ip和端口int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));if(res==-1){printf("绑定失败\n");//ip写错或者端口被占用return -1;}//3.创建监听队列res=listen(sockfd,5);if(res==-1){return -1;}return sockfd;}
客户端代码cli.c:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>int main()
{//1.创建套接字int sockfd=socket(AF_INET,SOCK_STREAM,0);if(sockfd==-1){exit(1);}//要连接服务器端就要知道服务器端的ip和端口,把ip和端口存到下面定义的saddr中struct sockaddr_in saddr;memset(&saddr,0,sizeof(saddr));//必须清空saddr.sin_family=AF_INET;saddr.sin_port=htons(6000);saddr.sin_addr.s_addr=inet_addr("127.0.0.1");//2.连接服务器端int res=connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));//会随机填充客户端的ip和一个临时端口if(res==-1)//网络没联通,服务器端没启动{printf("连接服务器端失败\n");exit(1);}while(1){char buff[128]={0};printf("输入:\n");fgets(buff,128,stdin);if(strncmp(buff,"end",3)==0){break;}//3.向服务器端发送消息send(sockfd,buff,strlen(buff),0);memset(buff,0,128);//4.接收服务器端回复的消息recv(sockfd,buff,127,0);printf("buff=%s\n",buff);}//5.关闭客户端printf("客户端关闭\n");close(sockfd);
}
运行结果:
此时,虽然两个客户端可以同时与服务器端通信,但是存在一个问题,就是僵死进程的问题,如下图:
之所以出现僵死进程是因为在子进程结束之后并没有处理子进程,在Linux系统中处理僵死进程的方法有两种,wait和忽略信号。
使用忽略信号的方式,服务器端的代码ser.c如下:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<pthread.h>
#include<signal.h>int socket_init();//封装一个套接字,套接字的声明
void do_run(int c)//子进程中处理客户端的方法的实现
{while(1){char buff[128]={0};int num=recv(c,buff,127,0);//相当于readif(num<=0){break;}printf("子进程接收到的信息:%s\n",buff);send(c,"ok",2,0);//相当于write}
}int main()
{signal(SIGCHLD,SIG_IGN);int sockfd=socket_init();//调用封装好的套接字方法,创建套接字if(sockfd==-1){printf("创建失败\n");exit(1);}while(1){struct sockaddr_in caddr;//定义客户端的套接字地址int len = sizeof(caddr);//4.接收客户端连接int c=accept(sockfd,(struct sockaddr*)&caddr,&len);if(c<0)//失败{continue;}printf("c=%d\n",c);//5.产生一个子进程来处理客户端的连接,子进程会复制父进程打开的所有文件,上面接收的客户端的连接c也算是文件描述符,这个c也会被复制到子进程中pid_t pid=fork();if(pid==-1) {printf("子进程产生失败\n"); close(c);//关闭c这个连接continue;//重新等待新的连接}else if(pid==0)//子进程产生成功{close(sockfd);//因为子进程不用sockfddo_run(c);//处理客户端,传入的参数是c这个描述符close(c);//子进程在退出之前关闭cprintf("子进程退出,pid=%d\n",getpid());exit(0);//处理完所连接的客户端,子进程必须要退出}else {close(c);//父进程关闭c连接,对子进程没有影响,因为在fork之后,描述符的引用计数加1,这时候父进程关闭,子进程也关闭,最终才能认为c被关闭//如果父进程不关闭c连接,c的值会一直增长}}exit(0);
}int socket_init()//套接字的具体实现
{int sockfd=socket(AF_INET,SOCK_STREAM,0);//1.创建套接字if(sockfd==-1){printf("创建失败\n");return -1;}struct sockaddr_in saddr;//定义服务器端的套接字地址memset(&saddr,0,sizeof(saddr));//清空saddr.sin_family=AF_INET;saddr.sin_port=htons(6000);saddr.sin_addr.s_addr=inet_addr("127.0.0.1");//2.绑定,指定套接字的ip和端口int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));if(res==-1){printf("绑定失败\n");//ip写错或者端口被占用return -1;}//3.创建监听队列res=listen(sockfd,5);if(res==-1){return -1;}return sockfd;}
或者使用wait方法,服务器端的代码ser.c如下:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<pthread.h>
#include<signal.h>int socket_init();//封装一个套接字,套接字的声明
void do_run(int c)//子进程中处理客户端的方法的实现
{while(1){char buff[128]={0};int num=recv(c,buff,127,0);//相当于readif(num<=0){break;}printf("子进程接收到的信息:%s\n",buff);send(c,"ok",2,0);//相当于write}
}
void fun(int sig)
{wait(NULL);
}
int main()
{signal(SIGCHLD,fun);int sockfd=socket_init();//调用封装好的套接字方法,创建套接字if(sockfd==-1){printf("创建失败\n");exit(1);}while(1){struct sockaddr_in caddr;//定义客户端的套接字地址int len = sizeof(caddr);//4.接收客户端连接int c=accept(sockfd,(struct sockaddr*)&caddr,&len);if(c<0)//失败{continue;}printf("c=%d\n",c);//5.产生一个子进程来处理客户端的连接,子进程会复制父进程打开的所有文件,上面接收的客户端的连接c也算是文件描述符,这个c也会被复制到子进程中pid_t pid=fork();if(pid==-1) {printf("子进程产生失败\n"); close(c);//关闭c这个连接continue;//重新等待新的连接}else if(pid==0)//子进程产生成功{close(sockfd);//因为子进程不用sockfddo_run(c);//处理客户端,传入的参数是c这个描述符close(c);//子进程在退出之前关闭cprintf("子进程退出,pid=%d\n",getpid());exit(0);//处理完所连接的客户端,子进程必须要退出}else {close(c);//父进程关闭c连接,对子进程没有影响,因为在fork之后,描述符的引用计数加1,这时候父进程关闭,子进程也关闭,最终才能认为c被关闭//如果父进程不关闭c连接,c的值会一直增长}}exit(0);
}int socket_init()//套接字的具体实现
{int sockfd=socket(AF_INET,SOCK_STREAM,0);//1.创建套接字if(sockfd==-1){printf("创建失败\n");return -1;}struct sockaddr_in saddr;//定义服务器端的套接字地址memset(&saddr,0,sizeof(saddr));//清空saddr.sin_family=AF_INET;saddr.sin_port=htons(6000);saddr.sin_addr.s_addr=inet_addr("127.0.0.1");//2.绑定,指定套接字的ip和端口int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));if(res==-1){printf("绑定失败\n");//ip写错或者端口被占用return -1;}//3.创建监听队列res=listen(sockfd,5);if(res==-1){return -1;}return sockfd;}
运行结果:
这次僵死进程就不存在了。
相关文章:
Linux 多进程解决客户端与服务器端通信
写一个服务器端用多进程处理并发,使两个以上的客户端可以同时连接服务器端得到响应。每当接受一个新的连接就fork产生一个子进程,让子进程去处理这个连接,父进程只用来接受连接。 与多线程相比的不同点:多线程如果其中一个线程操…...
Scala的模式匹配
Scala的模式匹配 Scala 中的模式匹配类似于Java 中的 switch 语法:下面是java中switch代码: int i 10 switch (i) {case 10 :System.out.println("10");break; case 20 :System.out.println("20");break; default :System.out.pr…...
HttPClient简介及示例:学习如何与Web服务器进行通信
文章目录 前言一、引入依赖二、使用步骤1.创建被调用者2.创建调用者三、结果被调用者服务:调用者服务: 总结 前言 欢迎来到本篇博客,这是一个关于HttPClient的入门案例的指南。🎉 在今天的网络世界中,与服务器进行数据…...
STS4 New 安装Spring Bean Configuration File
背景介绍 在创建spring项目后,如果想想创建spring bean Configuration的时候,发下菜单没有这个选项,需要通过下载Spring Roo插件可满足该操作。 参考案例 参考地址: STS4 New 菜单没有Spring Bean Configuration File选项_SQZHA…...
Java经典面试题(异或运算)
不爱生姜不吃醋⭐️⭐️⭐️ 🌻如果本文有什么错误的话欢迎在评论区中指正哦💗 🌻看完之后觉得不错的话麻烦动动小手点个赞赞吧👍 🌻与其明天开始,不如现在行动!💪 🌻大家…...
No primary or single unique constructor found for interface java.util.List
1.问题描述 前端 请求的参数 是 query形式, 参数在url中 报错信息: java.lang.IllegalStateException: No primary or single unique constructor found for interface java.util.List2.解决办法 controller中的 请求方法 参数 加上 RequestParam...
C#关于WebService中File.Exists()处理远程路径的异常记录
目录 前言方案一打开网站对应的程序池的高级设置按下图步骤设置凭据重启网站若方案一未能解决,请继续尝试方案二👇 方案二从控制面板进入到 凭据管理器为windows凭据添加凭据点击**Windows凭据**,并点击**添加Windows凭据**键入远程路径的地址…...
JavaWeb_LeadNews_Day10-Xxljob, Redis实现定时热文章
JavaWeb_LeadNews_Day10-Xxljob, Redis实现定时热文章 xxl-job概述windows部署调度中心docker部署调度中心 xxl-job入门案例xxl-job分片广播热点文章定时计算思路分析具体实现热文章计算定时计算 查询文章接口改造来源Gitee xxl-job概述 windows部署调度中心 运行 xxl-job\do…...
【WebRTC---源码篇】(二:二)视频源VideoSourceBase
作用 这个类继承自VideoSourceInterface<webrtc::VideoFrame>模板类,并且可以处理webrtc::VideoFrame class VideoSourceBase : public VideoSourceInterface<webrtc::VideoFrame> 重要成员变量 struct SinkPair {SinkPair(VideoSinkInterface<webrtc::Vid…...
Linux_8_磁盘存储和文件系统
1 磁盘结构 1.1 设备文件 一切皆文件: open(),read(),write(),close() 设备文件:关联至一个设备驱动程序,进而能够跟与之对应硬件设备进行通信 设备号码: 主设备号 major number,标识设备类型 次设备号 minor number,标识同一类型下的不同设备 设备类型:…...
VS + QT 封装带UI界面的DLL
一、创建编译DLL的项目 1.新建Qt Class Liabrary 2.新建项目,选择Qt Widgets Class 3.新建C类,可以在此类里面写算法函数用于调用。 4.下面是添加完Qt窗体类和C类之后的项目截图 5.修改头文件并编译 将uidemo_global.h中的ifdef内容复制到dialog.h上…...
逆向工程-架构真题(二十)
结构化程序设计采用自顶向下、逐步求精及模块化程序设计方法,通过()三种基本控制结构可以构造出任何单入口单出口程序。 顺序、选择和嵌套顺序、分支和循环分支、并发和循环跳转、选择和并发 答案:B 解析: 结构化设…...
Zookeeper 入门
第 1 章 Zookeeper 入门 1.1概述 Zookeeper从设计模式角度来理解:是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,Zookeeper就将…...
记录--前端使用a链接下载内容增加loading效果
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 问题描述:最近工作中出现一个需求,纯前端下载 Excel 数据,并且有的下载内容很多,这时需要给下载增加一个 loading 效果。 代码如下: // util…...
如何获取用户的ip地址
用户的 IP 地址可能会被隐藏或者修改,例如使用代理服务器、VPN 等工具,这样就无法准确获取用户的真实 IP 地址。 除了以上特殊情况,一般情况下 用户访问可能会经过一下链路 : 前端—>nginx—>网关—>服务 。 一般情况下后…...
单片机-控制按键点亮LED灯
1、按键电路图 定义四个按键引脚 1、按键按下 为 输入为低电平 2、按键不按下 IO有上拉电阻,为高电平 // 定义 按键的 管教 sbit KEY1 P3^1; sbit KEY2 P3^0; sbit KEY3 P3^2; sbit KEY4 P3^3; 2、LED灯电路图 LED 输出高电平为亮 // 定义LED灯 管教 sbit LED1…...
微信小程序新版隐私协议弹窗实现最新版
1. 微信小程序又双叒叕更新了 2023.08.22更新: 以下指南中涉及的 getPrivacySetting、onNeedPrivacyAuthorization、requirePrivacyAuthorize 等接口目前可以正常接入调试。调试说明: 在 2023年9月15号之前,在 app.json 中配置 __usePriva…...
GO语言圣经 第五章习题
练习5.1 修改findlinks代码中遍历n.FirstChild链表的部分,将循环调用visit,改成递归调用。 func visit(links []string, n *html.Node) []string {if n nil {return links}if n.Type html.ElementNode && n.Data "a" {for _, a : r…...
用kotlin 开发一个简单的多页面跳转
本文介绍一个简单的安卓应用的页面跳转例子,用的是kotlin。 运行时主页面是一个hello 和Jump 按钮,你按一下jump 按钮就转到 从页面,只是标识从页面。 开始建立一个简单工程,名为hello, 选择的是Empty views Activit…...
记录我的tensorrt 部署yolov8
系统 :ubuntu 18.04 代码 :GitHub - noahmr/yolov5-tensorrt: Real-time object detection with YOLOv5 and TensorRT conda 环境 : GitHub - noahmr/yolov5-tensorrt: Real-time object detection with YOLOv5 and TensorRT cuda : 11.8 …...
什么是用户界面? 优漫动游
什么是用户界面? 用户界面(UI,UserInterface)也称人机界面,是人机交互、操作逻辑和界面表现的整体设计。每一种设计都有其对应的职业角色,其中,人机交互的设计人员叫做用户研究工程师,操作逻辑设计人员叫…...
基于 Docker 的 MySQL 主从复制搭建(Mac M1版本)
系统:Macbook M1 镜像版本:mysql:5.7 如果是要查 slave连接不上 master的问题,可以直接跳到文章末尾踩坑处 准备工作 拉取镜像 docker pull mysql:5.7本地数据卷挂载 因为mysql不挂载的话,重启丢失数据,所以在本地创…...
【Locomotor运动模块】瞬移
文章目录 一、原理二、两种类型1、Instant(立刻)2、Dash(猛冲) 三、瞬移区域、瞬移点1、瞬移区域2、瞬移点 一、原理 抛物线指针选择好目标位置,然后告诉瞬移预设体:你想法把游戏区域弄到目标位置来 解释:抛物线指针选…...
【负载均衡】常见的负载均衡策略有哪些?
文章目录 前言负载均衡分类常见负载均衡策略小结 前言 负载均衡策略是实现负载均衡器的关键,而负载均衡器又是分布式系统中不可或缺的重要组件。使用它有助于提高系统的整体性能、可用性、可靠性和安全性,同时支持系统的扩展和故障容忍性。对于处理大量…...
ChatGPT如何应对紧急救援和医疗应急?
ChatGPT在紧急救援和医疗应急方面具有潜在的重要用途。它可以用于提供信息、建议和支持,以帮助应对各种突发事件,如自然灾害、流行病爆发、事故等。以下是ChatGPT如何应对紧急救援和医疗应急的方式以及相关挑战的详细讨论。 ### 紧急救援 #### 1. 提供…...
vue3 ref reactive响应式数据 赋值的问题
文章目录 vue3 ref reactive响应式数据 赋值的问题场景1:将响应式数据赋值请求后的数据错误示范:直接赋值正确写法 场景2:响应式数据解构之后失去响应式原因分析解决办法 toRefs/toRef方法创建ref引用对象 vue3 ref reactive响应式数据 赋值的问题 doing…...
【美团秋招】20230922小美的彩虹糖
小美的彩虹糖 小美有很多的彩虹糖,每颗彩虹糖都有一个颜色,她每天可以吃两颗彩虹糖,如果今天吃的彩虹糖组合是之前没吃过的组合,则小美今天会很高兴。 例如,小美有 6 颗彩虹糖,颜色分别是 [1,1,4,5,1,4]。…...
论文阅读_扩散模型_DM
英文名称: Deep Unsupervised Learning using Nonequilibrium Thermodynamics 中文名称: 使用非平衡热力学原理的深度无监督学习 论文地址: http://arxiv.org/abs/1503.03585 代码地址: https://github.com/Sohl-Dickstein/Diffusion-Probabilistic-Models 时间: 2015-11-18 作…...
【每日运维】RockyLinux8.6升级OpenSSH9.4p1
为什么需要升级openssh呢,因为很多项目进行漏扫结果都会涉及到这个服务器核心组件,一想到以前升级openssh带来的各种依赖性问题就头疼,不管是什么发行版,升级这个东西真的很烦,这次发现可能还会有好一点的通用一点的升…...
libdrm全解析三十八 —— 源码全解析(35)
接前一篇文章:libdrm全解析三十七 —— 源码全解析(34) 本文参考以下博文: DRM 驱动程序开发(VKMS) 特此致谢! 前一篇文章讲解完了drmModeSetCrtc(crtc_id, fb_id, connector_id, mode)&#…...
高端网站建设企业网站建站/登封seo公司
Set本身是一个构造函数,可以用来生成Set数据结构 1、初始化 Set中不允许有重复的值 2、属性 size:获取Set的长度 3、方法 add:向Set中添加任意类型的元素,重复添加无效,返回Set本身 delete:向Set中删除元素…...
网页制作门户网站案例/网站定制的公司
1.环境准备 1.1.初始化实例 安装DM数据库软件并初始化实例。始化实例请参考DM数据库相关的部署文档,本处不在赘述 1.2.创建元数据库 元数据库是用于保存监控平台的元数据的数据库。 1.3.调整数据库参数 调整DEM元数据库的参数(修改dm.in后重启生效&…...
安徽网站建设哪家好/网站建设的公司
2019独角兽企业重金招聘Python工程师标准>>> Frink:为物理计算设计的编程语言 作者:Alen 翻译:赖信涛 责编:仲培艺 Frink是一个实用的计算工具,也算是一种专为物理计算而设计的编程语言。它能让物理计算变得…...
台州网站建设公司/廊坊关键词快速排名
小Alan在最近的开发中遇到了敏感词过滤,便去网上查阅了很多敏感词过滤的资料,在这里也和大家分享一下自己的理解。敏感词过滤应该是不用给大家过多的解释吧?讲白了就是你在项目中输入某些字(比如输入xxoo相关的文字时)时要能检测出来…...
网站集约化建设汇报/手机百度搜索
文章目录前言一、大驼峰法(帕斯卡命名法)二、小驼峰法三、其他前言 驼峰命名法,是指混合使用大小写字母构成变量和函数名字。在Java开发中,建议使用驼峰命名法,增强代码的识别性和可读性。 一、大驼峰法(帕…...
网站建设公司优惠大酬宾活动/百度seo新规则
一般的类型和方法, 只能使用具体的类型: 要么是基本类型, 要么是自定义的类. 如果要编写可以应用于多种类型的代码, 这种刻板的 限制对代码的束缚就会很大 在面向对象编程中, 多态算是一种泛化机制, 你可以在方法的参数里使用基类的引用, 那么这个方法就可以使用这个基类的任…...