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

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 多进程解决客户端与服务器端通信

写一个服务器端用多进程处理并发&#xff0c;使两个以上的客户端可以同时连接服务器端得到响应。每当接受一个新的连接就fork产生一个子进程&#xff0c;让子进程去处理这个连接&#xff0c;父进程只用来接受连接。 与多线程相比的不同点&#xff1a;多线程如果其中一个线程操…...

Scala的模式匹配

Scala的模式匹配 Scala 中的模式匹配类似于Java 中的 switch 语法&#xff1a;下面是java中switch代码&#xff1a; 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.创建调用者三、结果被调用者服务&#xff1a;调用者服务&#xff1a; 总结 前言 欢迎来到本篇博客&#xff0c;这是一个关于HttPClient的入门案例的指南。&#x1f389; 在今天的网络世界中&#xff0c;与服务器进行数据…...

STS4 New 安装Spring Bean Configuration File

背景介绍 在创建spring项目后&#xff0c;如果想想创建spring bean Configuration的时候&#xff0c;发下菜单没有这个选项&#xff0c;需要通过下载Spring Roo插件可满足该操作。 参考案例 参考地址&#xff1a; STS4 New 菜单没有Spring Bean Configuration File选项_SQZHA…...

Java经典面试题(异或运算)

不爱生姜不吃醋⭐️⭐️⭐️ &#x1f33b;如果本文有什么错误的话欢迎在评论区中指正哦&#x1f497; &#x1f33b;看完之后觉得不错的话麻烦动动小手点个赞赞吧&#x1f44d; &#x1f33b;与其明天开始&#xff0c;不如现在行动&#xff01;&#x1f4aa; &#x1f33b;大家…...

No primary or single unique constructor found for interface java.util.List

1.问题描述 前端 请求的参数 是 query形式&#xff0c; 参数在url中 报错信息&#xff1a; java.lang.IllegalStateException: No primary or single unique constructor found for interface java.util.List2.解决办法 controller中的 请求方法 参数 加上 RequestParam...

C#关于WebService中File.Exists()处理远程路径的异常记录

目录 前言方案一打开网站对应的程序池的高级设置按下图步骤设置凭据重启网站若方案一未能解决&#xff0c;请继续尝试方案二&#x1f447; 方案二从控制面板进入到 凭据管理器为windows凭据添加凭据点击**Windows凭据**&#xff0c;并点击**添加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() 设备文件:关联至一个设备驱动程序&#xff0c;进而能够跟与之对应硬件设备进行通信 设备号码: ​ 主设备号 major number,标识设备类型​ 次设备号 minor number,标识同一类型下的不同设备 设备类型:…...

VS + QT 封装带UI界面的DLL

一、创建编译DLL的项目 1.新建Qt Class Liabrary 2.新建项目&#xff0c;选择Qt Widgets Class 3.新建C类&#xff0c;可以在此类里面写算法函数用于调用。 4.下面是添加完Qt窗体类和C类之后的项目截图 5.修改头文件并编译 将uidemo_global.h中的ifdef内容复制到dialog.h上…...

逆向工程-架构真题(二十)

结构化程序设计采用自顶向下、逐步求精及模块化程序设计方法&#xff0c;通过&#xff08;&#xff09;三种基本控制结构可以构造出任何单入口单出口程序。 顺序、选择和嵌套顺序、分支和循环分支、并发和循环跳转、选择和并发 答案&#xff1a;B 解析&#xff1a; 结构化设…...

Zookeeper 入门

第 1 章 Zookeeper 入门 1.1概述 Zookeeper从设计模式角度来理解&#xff1a;是一个基于观察者模式设计的分布式服务管理框架&#xff0c;它负责存储和管理大家都关心的数据&#xff0c;然后接受观察者的注册&#xff0c;一旦这些数据的状态发生变化&#xff0c;Zookeeper就将…...

记录--前端使用a链接下载内容增加loading效果

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 问题描述&#xff1a;最近工作中出现一个需求&#xff0c;纯前端下载 Excel 数据&#xff0c;并且有的下载内容很多&#xff0c;这时需要给下载增加一个 loading 效果。 代码如下&#xff1a; // util…...

如何获取用户的ip地址

用户的 IP 地址可能会被隐藏或者修改&#xff0c;例如使用代理服务器、VPN 等工具&#xff0c;这样就无法准确获取用户的真实 IP 地址。 除了以上特殊情况&#xff0c;一般情况下 用户访问可能会经过一下链路 &#xff1a; 前端—>nginx—>网关—>服务 。 一般情况下后…...

单片机-控制按键点亮LED灯

1、按键电路图 定义四个按键引脚 1、按键按下 为 输入为低电平 2、按键不按下 IO有上拉电阻&#xff0c;为高电平 // 定义 按键的 管教 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更新&#xff1a; 以下指南中涉及的 getPrivacySetting、onNeedPrivacyAuthorization、requirePrivacyAuthorize 等接口目前可以正常接入调试。调试说明&#xff1a; 在 2023年9月15号之前&#xff0c;在 app.json 中配置 __usePriva…...

GO语言圣经 第五章习题

练习5.1 修改findlinks代码中遍历n.FirstChild链表的部分&#xff0c;将循环调用visit&#xff0c;改成递归调用。 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 开发一个简单的多页面跳转

本文介绍一个简单的安卓应用的页面跳转例子&#xff0c;用的是kotlin。 运行时主页面是一个hello 和Jump 按钮&#xff0c;你按一下jump 按钮就转到 从页面&#xff0c;只是标识从页面。 开始建立一个简单工程&#xff0c;名为hello&#xff0c; 选择的是Empty views Activit…...

记录我的tensorrt 部署yolov8

系统 &#xff1a;ubuntu 18.04 代码 &#xff1a;GitHub - noahmr/yolov5-tensorrt: Real-time object detection with YOLOv5 and TensorRT conda 环境 &#xff1a; GitHub - noahmr/yolov5-tensorrt: Real-time object detection with YOLOv5 and TensorRT cuda : 11.8 …...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架&#xff0c;相比 MapReduce 具有以下核心优势&#xff1a; 内存计算&#xff1a;数据可常驻内存&#xff0c;迭代计算性能提升 10-100 倍&#xff08;文档段落&#xff1a;3-79…...

【机器视觉】单目测距——运动结构恢复

ps&#xff1a;图是随便找的&#xff0c;为了凑个封面 前言 在前面对光流法进行进一步改进&#xff0c;希望将2D光流推广至3D场景流时&#xff0c;发现2D转3D过程中存在尺度歧义问题&#xff0c;需要补全摄像头拍摄图像中缺失的深度信息&#xff0c;否则解空间不收敛&#xf…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享

文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的&#xff0c;根据Excel列的需求预估的工时直接打骨折&#xff0c;不要问我为什么&#xff0c;主要…...

MMaDA: Multimodal Large Diffusion Language Models

CODE &#xff1a; https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA&#xff0c;它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1

每日一言 生活的美好&#xff0c;总是藏在那些你咬牙坚持的日子里。 硬件&#xff1a;OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写&#xff0c;"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

微服务商城-商品微服务

数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南

精益数据分析&#xff08;97/126&#xff09;&#xff1a;邮件营销与用户参与度的关键指标优化指南 在数字化营销时代&#xff0c;邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天&#xff0c;我们将深入解析邮件打开率、网站可用性、页面参与时…...

以光量子为例,详解量子获取方式

光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学&#xff08;silicon photonics&#xff09;的光波导&#xff08;optical waveguide&#xff09;芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中&#xff0c;光既是波又是粒子。光子本…...

AGain DB和倍数增益的关系

我在设置一款索尼CMOS芯片时&#xff0c;Again增益0db变化为6DB&#xff0c;画面的变化只有2倍DN的增益&#xff0c;比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析&#xff1a; 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...