多线程多进程处理服务器并发(多进程处理如何解决僵死进程)

2024-03-13 20:44

本文主要是介绍多线程多进程处理服务器并发(多进程处理如何解决僵死进程),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

1.可循环发送数据的代码

2.改成循环之后每次发现只能处理一个客户端 

3.服务器端处理并发问题

3.1 思路

3.2 利用多线程实现并发

​编辑

3.3 利用多进程实现并发

3.3.1 多进程并发产生的僵死进程问题

​3.3.2 解决僵死进程问题


1.可循环发送数据的代码

服务器代码:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
int main()
{int sockfd=socket(AF_INET,SOCK_STREAM,0);//监听套接字assert(sockfd!=-1);struct sockaddr_in saddr,caddr;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");//IP地址转换int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));assert(res!=-1);res=listen(sockfd,5);assert(res!=-1);while(1){int len=sizeof(saddr);printf("accept wait...\n");int c=accept(sockfd,(struct sockaddr*)&caddr,&len);//链接套接字if(c<0){continue;}printf("accept c=%d\n",c);printf("accept client ip:%s ,port=%d\n",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));while(1){	char buff[128]={0};int n=recv(c,buff,127,0);//返回值为0说明断开连接if(n<=0){break;}printf("buff=%s\n",buff);send(c,"ok",2,0);}close(c);}close(sockfd);exit(0);
}

 客户端代码:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
int main()
{int sockfd=socket(AF_INET,SOCK_STREAM,0);//监听套接字assert(sockfd!=-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");int res=connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));assert(res!=-1);while(1){printf("input:\n");char buff[128]={0};fgets(buff,127,stdin);if(strncmp(buff,"end",3)==0){break;}send(sockfd,buff,strlen(buff),0);memset(buff,0,128);recv(sockfd,buff,127,0);printf("read:%s\n",buff);}close(sockfd);exit(0);
}

运行结果:

2.改成循环之后每次发现只能处理一个客户端 

将代码从单词发送数据改为while(1)循环发送数据后,我们发现每次只能处理一个客户端,其它客户端消息无法发送给服务器。

原因: 

3.服务器端处理并发问题

3.1 思路

这个问题可以通过引入多线程和多进程来解决。

服务端接收一个客户端的连接后(accept之后),创建一个线程或者进程,然后在新创建的线程或进程中循环处理数据。

主线程(父进程)只负责监听客户端的连接,并使用 accept()接受连接,不进行数据的处理。如下图所示: 

3.2 利用多线程实现并发

客户端代码不变,服务器端代码做如下更改:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <pthread.h>
void* work_pthread(void*arg)
{	int c=*(int*)arg;while(1){char buff[128]={0};int n=recv(c,buff,127,0);//返回值为0说明断开连接if(n<=0){break;}printf("recv(%d)=%s\n",c,buff);send(c,"ok",2,0);}printf("one clinet over!\n");close(c);
}int main()
{int sockfd=socket(AF_INET,SOCK_STREAM,0);//监听套接字assert(sockfd!=-1);struct sockaddr_in saddr,caddr;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");//IP地址转换int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));assert(res!=-1);res=listen(sockfd,5);assert(res!=-1);while(1){int len=sizeof(saddr);printf("accept wait...\n");int c=accept(sockfd,(struct sockaddr*)&caddr,&len);//链接套接字if(c<0){continue;}printf("accept c=%d\n",c);printf("accept client ip:%s ,port=%d\n",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));pthread_t id;pthread_create(&id,NULL,work_pthread,(void*)&c);}close(sockfd);exit(0);
}

netstat -natp连接成功之后发现有两个./ser

3.3 利用多进程实现并发

客户端代码不变,服务器代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>void DealClientLink(int c,struct sockaddr_in caddr)
{while(1){char buff[128]={0};int n=recv(c,buff,127,0);//返回值为0说明断开连接if(n<=0){break;}printf("%s:%d:buff=%s\n",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port),buff);send(c,"ok",2,0);}printf("one clinet unlike!\n");close(c);
}int main()
{int sockfd=socket(AF_INET,SOCK_STREAM,0);//监听套接字assert(sockfd!=-1);struct sockaddr_in saddr,caddr;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");//IP地址转换int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));assert(res!=-1);res=listen(sockfd,5);assert(res!=-1);printf("%s:%d link success!\n",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));while(1){int len=sizeof(saddr);int c=accept(sockfd,(struct sockaddr*)&caddr,&len);//链接套接字if(c<0){continue;}pid_t pid=fork();assert(pid!=-1);if(pid==0){DealClientLink(c,caddr);exit(0);}}close(sockfd);exit(0);
}

 运行结果:

3.3.1 多进程并发产生的僵死进程问题

子进程为客户端,父进程为服务器端,子进程先于父进程结束,父进程没有获取到子进程的退出码,子进程就会变成僵死进程,占用内存,影响执行速度。

客户端代码运行前:

关闭客户端(子进程结束)后:

如下图,产生了两个僵死进程。

 3.3.2 解决僵死进程问题

修改一下代码,让父进程调用wait()方法获取子进程的退出码,并结合信号使用,让它不再阻塞。

#include <wait.h>void fun(int sig)
{wait(&sig);
}signal(SIGCHLD,fun);//在主进程中添加

完整代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <wait.h>void DealClientLink(int c,struct sockaddr_in caddr)
{while(1){char buff[128]={0};int n=recv(c,buff,127,0);//返回值为0说明断开连接if(n<=0){break;}printf("%s:%d:buff=%s\n",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port),buff);send(c,"ok",2,0);}printf("one clinet unlike!\n");close(c);
}void fun(int sign)
{wait(&sign);
}int main()
{signal(SIGCHLD,fun);int sockfd=socket(AF_INET,SOCK_STREAM,0);//监听套接字assert(sockfd!=-1);struct sockaddr_in saddr,caddr;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");//IP地址转换int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));assert(res!=-1);res=listen(sockfd,5);assert(res!=-1);printf("%s:%d link success!\n",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));while(1){int len=sizeof(saddr);int c=accept(sockfd,(struct sockaddr*)&caddr,&len);//链接套接字if(c<0){continue;}pid_t pid=fork();assert(pid!=-1);if(pid==0){DealClientLink(c,caddr);exit(0);}}close(sockfd);exit(0);
}

 使用ps -f命令查看进程信息,可以看到子进程退出后,没有僵死进程。

这篇关于多线程多进程处理服务器并发(多进程处理如何解决僵死进程)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/806147

相关文章

服务器集群同步时间手记

1.时间服务器配置(必须root用户) (1)检查ntp是否安装 [root@node1 桌面]# rpm -qa|grep ntpntp-4.2.6p5-10.el6.centos.x86_64fontpackages-filesystem-1.41-1.1.el6.noarchntpdate-4.2.6p5-10.el6.centos.x86_64 (2)修改ntp配置文件 [r

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关

如何解决线上平台抽佣高 线下门店客流少的痛点!

目前,许多传统零售店铺正遭遇客源下降的难题。尽管广告推广能带来一定的客流,但其费用昂贵。鉴于此,众多零售商纷纷选择加入像美团、饿了么和抖音这样的大型在线平台,但这些平台的高佣金率导致了利润的大幅缩水。在这样的市场环境下,商家之间的合作网络逐渐成为一种有效的解决方案,通过资源和客户基础的共享,实现共同的利益增长。 以最近在上海兴起的一个跨行业合作平台为例,该平台融合了环保消费积分系统,在短

【生成模型系列(初级)】嵌入(Embedding)方程——自然语言处理的数学灵魂【通俗理解】

【通俗理解】嵌入(Embedding)方程——自然语言处理的数学灵魂 关键词提炼 #嵌入方程 #自然语言处理 #词向量 #机器学习 #神经网络 #向量空间模型 #Siri #Google翻译 #AlexNet 第一节:嵌入方程的类比与核心概念【尽可能通俗】 嵌入方程可以被看作是自然语言处理中的“翻译机”,它将文本中的单词或短语转换成计算机能够理解的数学形式,即向量。 正如翻译机将一种语言

高并发环境中保持幂等性

在高并发环境中保持幂等性是一项重要的挑战。幂等性指的是无论操作执行多少次,其效果都是相同的。确保操作的幂等性可以避免重复执行带来的副作用。以下是一些保持幂等性的常用方法: 唯一标识符: 请求唯一标识:在每次请求中引入唯一标识符(如 UUID 或者生成的唯一 ID),在处理请求时,系统可以检查这个标识符是否已经处理过,如果是,则忽略重复请求。幂等键(Idempotency Key):客户端在每次

Linux服务器Java启动脚本

Linux服务器Java启动脚本 1、初版2、优化版本3、常用脚本仓库 本文章介绍了如何在Linux服务器上执行Java并启动jar包, 通常我们会使用nohup直接启动,但是还是需要手动停止然后再次启动, 那如何更优雅的在服务器上启动jar包呢,让我们一起探讨一下吧。 1、初版 第一个版本是常用的做法,直接使用nohup后台启动jar包, 并将日志输出到当前文件夹n

[Linux]:进程(下)

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:Linux学习 贝蒂的主页:Betty’s blog 1. 进程终止 1.1 进程退出的场景 进程退出只有以下三种情况: 代码运行完毕,结果正确。代码运行完毕,结果不正确。代码异常终止(进程崩溃)。 1.2 进程退出码 在编程中,我们通常认为main函数是代码的入口,但实际上它只是用户级

pip-tools:打造可重复、可控的 Python 开发环境,解决依赖关系,让代码更稳定

在 Python 开发中,管理依赖关系是一项繁琐且容易出错的任务。手动更新依赖版本、处理冲突、确保一致性等等,都可能让开发者感到头疼。而 pip-tools 为开发者提供了一套稳定可靠的解决方案。 什么是 pip-tools? pip-tools 是一组命令行工具,旨在简化 Python 依赖关系的管理,确保项目环境的稳定性和可重复性。它主要包含两个核心工具:pip-compile 和 pip

【VUE】跨域问题的概念,以及解决方法。

目录 1.跨域概念 2.解决方法 2.1 配置网络请求代理 2.2 使用@CrossOrigin 注解 2.3 通过配置文件实现跨域 2.4 添加 CorsWebFilter 来解决跨域问题 1.跨域概念 跨域问题是由于浏览器实施了同源策略,该策略要求请求的域名、协议和端口必须与提供资源的服务相同。如果不相同,则需要服务器显式地允许这种跨域请求。一般在springbo

Thymeleaf:生成静态文件及异常处理java.lang.NoClassDefFoundError: ognl/PropertyAccessor

我们需要引入包: <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>sp