简单进程池实现多TCP客户服务

池——线程池、进程池、内存池、连接池 为什么要使用线程池和进程池? (1)动态创建子进程(子线程)是比较耗时的,这将导致较慢的客户响应 (2)动态创建的子进程(或子线程)通常只用来为一个客户服务(除非做特殊处理),这将导致系统上产生大量的细微进程(或线程)。进程(或线程)间的切换将消耗大量的CPU (3)动态创建的子进程是当前进程的完整映像当前进程必须谨慎地管理其分配的文件描述符和堆内存等系统资源,否则子进程可能复制这些资源,... 阅读详情

根据预定义进程数创建进程池。

父子进程通信使用的IPC方式为:UNIX域套接字

父进程listen,aeecpt,并将连接套接字发送到子进程,交由子进程处理该连接。

子进程处理完毕,与父进程通信,实现资源回收,并在下一连接到来交由该完毕的子进程。

#include "unp.h"
#include <assert.h>
#define IDLE		0
#define BUSY		1
#define END		2


typedef struct pro {
	pid_t	id;		/*进程的进程ID*/
	int 		fd;		/*与父进程通信的描述符*/
	int		flags;	/*进程当前状态*/
	int		cnt;		/*进程服务的次数*/
}process;
process	*mypid;		/*进程池*/


ssize_t write__the_fd(int fd, void *ptr, size_t nbytes, int sendfd);
pid_t make_child( int i, int listenfd );
ssize_t read_the_fd(int fd, void *ptr, size_t nbytes, int *recvfd);
void child_func( void);
void clr(int signo);
int	main( int argc, char **argv ) {
	int 		nchild, fdmax, listenfd, connfd, i, len, nselect;
	char		c;
	struct sockaddr_in		addr, clientaddr;
	signal(SIGCHLD, clr);
	signal(SIGINT, clr);
	fd_set	rset, oset;
	if(argc != 2)
		err_quit("args");
	listenfd = socket( AF_INET, SOCK_STREAM, 0 );/*服务器监听套接字*/
	if( listenfd < 0 ) {
		err_sys("socket");
	}
	nchild = atoi(argv[1]);
	mypid = (struct pro *)malloc( nchild * sizeof( struct pro) );
	bzero( &addr, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_port	 = htons(SERV_PORT);
	addr.sin_addr.s_addr = htonl(INADDR_ANY);
	bind(listenfd, (SA *)&addr, sizeof(struct sockaddr));
	fdmax = listenfd; 						/*用于select */
	for( i = 0; i < nchild; i++ ) {
		make_child(i, listenfd);				/*创建子进程并等待给客户服务*/
	}									/*传入listenfd子进程关闭监听套接字*/
	int idle = nchild;						/*当前空闲的子进程*/
	len = sizeof(struct sockaddr);
	FD_ZERO(&oset);
	FD_ZERO(&rset);
	listen(listenfd,5);
	FD_SET(listenfd, &oset);
	for( ; ;) {
		if(idle == 0) 
			FD_CLR(listenfd, &oset);		/*若没有空闲子进程,则禁止accept新连接*/
		else 
			FD_SET(listenfd, &oset);	
		rset = oset;
		nselect = select(fdmax+1, &rset, NULL, NULL, NULL);
		if( FD_ISSET(listenfd, &rset) ) {		/*收到客户端连接请求*/
			connfd = accept(listenfd, (SA *)&clientaddr, &len);
			for( i = 0; i < nchild; i++) {
				if(mypid[i].flags == IDLE) {	/*查找可供服务的子进程*/
					break;
				}
			}
			/*  */
			assert(i < nchild);
			/*  */
			//connfd = accept(listenfd, (SA *)&clientaddr, &len);
			printf("the id is %d \n",i);
			mypid[i].flags = BUSY;  				/*改变子进程状态*/
			mypid[i].cnt ++;						/*子进程服务次数*/
			FD_SET(mypid[i].fd, &oset);				/*加入描述集,等待子进程*/
			fdmax = max(fdmax ,mypid[i].fd);
			idle --;								/*空闲进程减少*/
			/*通知子进程*/
			write_the_fd(mypid[i].fd, " ", 1,connfd);/*把连接套接字传送给子进程*/
			close(connfd);						/*因为有有一个confd在飞,所以这个可以关闭*/
			if(--nselect  ==0)
				continue;
		}
		else {
			for(i = 0; i < nchild; i++ ) {
				if(FD_ISSET(mypid[i].fd , &rset)) {
					read(mypid[i].fd, &c, 1);
					mypid[i].flags = IDLE;
					FD_CLR(mypid[i].fd, &oset);
					idle ++;
				}
				if(--nselect  == 0)
					break;
			}

		}
		
		
	}
}
void clr(int signo) {
	pid_t pid;
	while( (pid = waitpid(-1, NULL, WNOHANG)) > 0 ) {
		printf("The child %d is done\n", pid);
	}
	sleep(2);
	kill(getpid(), SIGTERM);
	return;
}
pid_t make_child( int i, int listenfd ) {
	pid_t 	child;
	int		fd[2];
	socketpair( AF_LOCAL, SOCK_STREAM,0, fd);
	if( (child = fork( ) ) < 0 ) {
		err_quit("fork ");
	}
	if( child > 0 ) {  /*父进程*/
		//printf("the  i is  %d\n", i);
		close( fd[1] );
		mypid[i].id = child;
		mypid[i].fd= fd[0];
		mypid[i].flags = IDLE;
		mypid[i].cnt = 0;
		return child;
	}
	/*子进程*/
	close( fd[0] );
	close(listenfd);
	dup2( fd[1], STDERR_FILENO);
	close( fd[1]);
	child_func();
}

void child_func( void) {
	int 		connfd, n;
	char		c;
	char		buf[MAXLINE];
	for( ; ; ) {
		n = read_fd(STDERR_FILENO, &c, 1, &connfd);
		if(n <0 ) 
			err_sys("read_fd");
		again:
		while( (n = read(connfd, buf, sizeof(buf))) > 0 ){
			writen(connfd, buf ,n);
		}
		if((n < 0)&&( errno == EINTR))
			goto again;
		else if(n < 0)
			err_sys("error");
		else if(n ==0) {
			close(connfd);
			write(STDERR_FILENO, " ", 1);
		}
	}
}
ssize_t write_the_fd(int fd, void *ptr, size_t nbytes, int sendfd) {
	struct msghdr	msg;
	struct iovec	iov[1];
	union {
	  struct cmsghdr	cm;
	  char				control[CMSG_SPACE(sizeof(int))];
	} control_un;
	struct cmsghdr	*cmptr;
	msg.msg_control = control_un.control;
	msg.msg_controllen = sizeof(control_un.control);
	cmptr = CMSG_FIRSTHDR(&msg);
	cmptr->cmsg_len = CMSG_LEN(sizeof(int));
	cmptr->cmsg_level = SOL_SOCKET;
	cmptr->cmsg_type = SCM_RIGHTS;
	*((int *) CMSG_DATA(cmptr)) = sendfd;
	msg.msg_name = NULL;
	msg.msg_namelen = 0;
	iov[0].iov_base = ptr;
	iov[0].iov_len = nbytes;
	msg.msg_iov = iov;
	msg.msg_iovlen = 1;
	return(sendmsg(fd, &msg, 0));
}
ssize_t read_the_fd(int fd, void *ptr, size_t nbytes, int *recvfd) {
	struct msghdr	msg;
	struct iovec	iov[1];
	ssize_t			n;
	int				newfd;
	union {
	  struct cmsghdr	cm;
	  char				control[CMSG_SPACE(sizeof(int))];
	} control_un;
	struct cmsghdr	*cmptr;

	msg.msg_control = control_un.control;
	msg.msg_controllen = sizeof(control_un.control);
	msg.msg_name = NULL;
	msg.msg_namelen = 0;

	iov[0].iov_base = ptr;
	iov[0].iov_len = nbytes;
	msg.msg_iov = iov;
	msg.msg_iovlen = 1;

	if ( (n = recvmsg(fd, &msg, 0)) <= 0)
		return(n);
	if ( (cmptr = CMSG_FIRSTHDR(&msg)) != NULL &&
	    cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
		if (cmptr->cmsg_level != SOL_SOCKET)
			err_quit("control level != SOL_SOCKET");
		if (cmptr->cmsg_type != SCM_RIGHTS)
			err_quit("control type != SCM_RIGHTS");
		*recvfd = *((int *) CMSG_DATA(cmptr));
	} else
		*recvfd = -1;		
	return(n);
}


解决windows10下无法安装.net framework 3.5(包括.net2.0和3.0) 入域电脑,win10系统中安装 .net framework 3.5(包括.net2.0和3.0) 阅读详情

相关推荐

保姆级教程:用LoRA微调Chinese-Mistral-7B模型,并一键部署到Ollama(附完整代码)

本文提供了一份详细的LoRA微调Chinese-Mistral-7B模型的保姆级教程,涵盖环境配置、数据预处理、微调实战、模型量化及Ollama部署全流程。通过实战案例和完整代码,帮助开发者快速构建专属中文大模型,适用于医疗、法律等垂直领域。

weixin_30369041的博客 250

javaweb原理

一、HTTP协议的理解 1.       什么是HTTP协议 HTTP是一种超本文传输协议,是一套计算机在网络中通信的规则。他是一种无状态的传输方式。 2.       HTTP协议的格式 HTTP的请求:         请求行(HTTP方法、请求的URL、HTTP版本)、 请求头(Host、User-Agent、Aeecpt)、 空行、消息体 HTTP的响应:        

u012540631的专栏 479

CH340驱动安装全攻略:从Windows到MacOS的避坑指南(2025最新版)

本文提供2025年最新版CH340驱动安装全攻略,涵盖Windows、MacOS和Linux三大操作系统。详细解析了驱动安装的核心原理、标准流程,并针对Windows设备管理器报错、MacOS系统安全限制等常见“坑点”提供了深度排错与解决方案,旨在帮助开发者快速稳定地完成USB转串口通信配置。

earth的博客 426

文件上传接受的类型:file的accept属性

&lt;input id="fileId1" type="file" accept="image/png,image/gif" name="file" /&gt; 后缀名 MIME名称 *.3gpp audio/3gpp, video/3gpp *.ac3 audio/ac3 *.asf allpication/vnd.ms-asf *.au ...

qq_29854831的博客 3万+

海康视觉通讯配置

本文介绍了海康通讯管理中TCP和Modbus协议的配置方法。TCP通讯时,视觉系统作为服务器接收PLC客户端发送的触发信号,需注意十进制与十六进制字符串的转换。Modbus配置需填写PLC的IP地址和寄存器首地址,并预先定义整型变量。TCP通讯需开启16进制发送模式以避免数据格式问题。文章重点说明了不同通讯方式下的数据格式转换和参数设置要点。

A567852的博客 2243

使用ChIPSeeker进行ChIP-seq, ATAC-seq,cut&tag等富集峰的基因组注释

常规的下一代高通量测序(next generation sequencing, NGS)实验通常产生大量短片段(reads),通常我们需要将这些reads比对到参考基因组/转录组上,即将它们置于生物学上有意义的基因背景下,才能获得有意义的结果。一般我们认为会产生两种类型的数据(当然两者并无严格意义上的区分)

微生信 3320

input type=file accept中限制文件类型pdf、doc、docx、 jpg、 png、xls 、xlsx等格式

accept="application/msexcel,application/msword,application/pdf,image/jpeg,image/png,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.openxmlformats-officedocument.wor...

usuallyuser的博客 3万+

DeepSeek R1-32B医疗大模型的完整微调实战分析(全码版)

【代码】DeepSeek R1-32B医疗大模型的完整微调实战指南(全码版)

AllenLV的博客 5102

accept函数详解

既然服务端已经很虔诚了,很真诚了,处于倾听状态,那么该是去尝试接受客户端请求的时候了,别只顾着倾听,不去接纳别人。接纳客户端请求的函数是accept, 我们先来看看函数的原型: WINSOCK_API_LINKAGE SOCKET WSAAPI accept( SOCKET s, struct sockaddr FAR * addr, int FAR * ad

认知 行动 坚持 7万+

ABAP Module Pool 编程入门:把 Table Control 用透,在 Dynpro 里做出可编辑的列表界面

摘要:Table Control是SAP GUI中用于对话式事务的多行数据交互控件,具备滚动、选择、修改等功能。它通过CXTAB_CONTROL/CXTAB_COLUMN结构实现动态控制,需在PBO/PAI中配合LOOP循环处理数据流。开发时需注意LINES、TOP_LINE等关键字段设置,并采用并行循环简化编码。典型应用包括订单行维护、主数据管理等场景,支持多选删除、列排序等业务需求。(150字)

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 344

Opencv项目实战:20 单手识别数字0到5

今天要做的是单手识别数字0到5,通过在窗口展示,实时的展示相应的图片以及文字。在这里,我提供一下识别更多数字的方法(0-10)。首先最简便的是双手识别,完全不用更改代码,把图片处理好就行了;其次,就是按照最上面的那张图片,参数figureup是一个长度为5的列表[0,0,0,0,0],你可以参照着手势将其打印出来,然后将其用if条件判断。当然,在我们这边最常见的还是华北手势表示数字,大家按照自己的习惯来就行。

m0_62919535的博客 2877

linux网络编程:使用进程池实现TCP多客户服务

进程池服务:让服务器在启动的某个阶段创建一个进程池,每个客户请求由当前可用子进程池中的某个(闲置)子进程处理。使用进程池的优点在于可以节省fork的开销直接就能处理新到的客户。缺点就是父进程必须父进程必须在服务器启动阶段猜测需要预先派生多少子进程。如果某个时刻客户数恰好等于子子进程总数,那么新到的客户将会被忽略,直到有一个子进程可以被重新使用。如果启动的时候创建过多的子进程,那么就会出现进...

Biao 910

fragstats:景观指数趋势分析

优快云@_养乐多_本文将介绍景观指数时间序列的趋势分析,包括趋势类型、斜率、截距等。以及景观指数突变分析所用的软件和 python 代码。结果如下图所示,

养乐多的博客 2861

14. 进程池和线程池

之前的章节中,我们通过动态创建子进程或子线程来实现并发服务器,这样做的缺点有: + 动态创建进程或线程比较耗时,这将导致较慢的客户响应。 + 动态创建的子进程或子线程通常只用来为一个客户服务(除非我们做特殊处理),这将导致系统上产生大量的细微进程或线程,进程或线程间的切换将消耗大量CPU时间。 + 动态创建的子进程是当前

Teriri_的博客 932

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

进程池

进程池 进程池的使用场景 当我们需要并行的处理大规模任务的时候,需要使用到多进程,多线程技术,比如说服务器处理大量客户端的任务,我在大一的时候写过一个C/S+mysql架构的聊天室,大概是这样处理的,每当有客户端发出连接请求时,服务器accept成功以后就去fork一个进程去处理关于这个客户端的所有请求,经过后来的一系列的学习,这显然是极其不科学的,狂开进程浪费资源且不说,效率也极低。 动态创建...

Holy_666的博客 578

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

Linux进程池的实现

通过动态创建子进程(或者子线程)来实现并发服务器的。这样做有如下缺点: 1、 动态创建进程(或线程)是比较耗费时间的,这将导致较慢的客户响应。 2、动态创建的子进程(或子线程)通常只用来为一个客户服务(除非我们做特殊处理),这将导致系统上产生大量的细微进程(或者线程)。进程(或者线程)间的切换消费大量CPU时间。 3、动态创建的子进程是当前进程的完整映像。当前进程...

Al_xin的专栏 6191

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Linux 网络编程学习笔记——十五、进程池和线程池

在前面的章节中,我们是通过动态创建子进程(或子线程)来实现并发服务器的。这样做有如下缺点:本章将分析这两种“池”的细节,给出它们的通用实现,并分别用进程池和线程池来实现简单的并发服务器。进程池和线程池相似,所以这里我们只以进程池为例进行介绍。如没有特殊声明,下面对进程池的讨论完全适用于线程池。进程池是由服务器预先创建的一组子进程,这些子进程的数目在 3 ~ 10 个之间(典型情况)。比如 httpd 守护进程就是使用包含 7 个子进程的进程池来实现并发的。线程池中的线程数量应该和 CPU 数量差不多。进程池

BeZer0的学习笔记 1万+

(转)Linux进程池的实现

原文地址: http://m.blog.youkuaiyun.com/blog/yhc13429826359/39258067 通过动态创建子进程(或者子线程)来实现并发服务器的。这样做有如下缺点:    1、  动态创建进程(或线程)是比较耗费时间的,这将导致较慢的客户响应。    2、动态创建的子进程(或子线程)通常只用来为一个客户服务(除非我们做特殊处理),这将导致系统上产生大量的细微

无名小鱼 997

《Linux高性能服务器编程》第十五章 进程池和线程池

Github代码地址 第15章 进程池和线程池 第15章 进程池和线程池

qq_39274501的博客 646

Linux高性能服务器编程 学习笔记 第十五章 进程池和线程池

我们接下来实现上图所示的半同步/半反应堆模式的线程池,相比以上进程池的实现,该线程池的通用性要高得多,因为它使用一个工作队列完全解除了主线程和工作线程的耦合关系:主线程往工作队列插入任务,工作线程通过竞争来取得任务并执行它。2.主进程和所有子进程通过一个共享的工作队列来同步,子进程都睡眠在该工作队列上,当有新任务到来时,主进程将任务添加到工作队列中,这将唤醒正在等待任务的子进程,但只有一个子进程能获得新任务的接管权,它可以从工作队列中取出任务并执行之,而其他子进程将继续睡眠在工作队列上。

tus00000的博客 478

15.Linux 高性能服务器编程 --- 进程池和线程池

1.动态创建进程和线程缺点: 1.动态创建进程(或线程)比较耗费时间 2.动态创建的子进程(或子线程)通常只用来为一个客户服务,这将导致系统上产生大量的细微进程(或线程)。 进程(或线程)间的切换将消耗大量CPU时间。 3.动态创建的子进程是当前进程的完整映像。当前进程必须谨慎的管理其分配的文件描述符和堆内存等系统资源。 否则子进程可能复制这些资源,从而使系统的可用资源急剧下降,进而影...

enlyhua的专栏 885

Linux服务器——进程/线程池

以进程池为例,若无特殊说明,下面对进程池的讨论完全适用于线程池。进程池中的所有子进程都运行着相同的代码,并具有相同的属性,比如优先级、PGID 等。因为进程池在服务器启动之初就创建好了,所以每个子进程都相对干净。主进程使用某种算法来主动选择子进程。主进程和所有子进程通过一个共享的工作队列来同步,子进程都睡眠在该工作队列上。在父进程和子进程之间预先建立好一条管道,然后通过该管道来实现所有的进程间通信;在父线程和子线程之间传递数据就比较方便,可以把这些数据定义为全局的;

Lassi的博客 239

客户-服务器程序设计方法

客户-服务器程序设计方法 《unix网络编程》第一卷中将传统的客户服务器程序设计方法讲得透彻,这篇文章将其中编码的细节略去,通过伪代码的形式展现,主要介绍各种方法的思想;(后面再续上一篇现代服务器的主要设计方法,基本是围绕这Reactor做文章) 示例是一个经典的TCP回射程序: 客户端发起连接请求,连接后发送一串数据;收到服务端的数据后输出到终端; 服务端收到客户端的数据后...

weixin_30411239的博客 303

CentOS 7下Apache+PHP-FPM多PHP版本共存实战

PHP多版本共存是LAMP架构中保障遗留系统兼容性与新特性演进的关键技术方案。其核心原理在于解耦Web服务器与PHP执行环境,通过FastCGI协议实现请求路由与进程隔离。Apache的mod_proxy_fcgi模块配合PHP-FPM的多池化管理,支持按虚拟主机或子目录精准绑定不同PHP解释器,天然规避mod_php单版本硬绑定缺陷。该方案显著提升运维安全性(如老版本限权运行)、资源可控性(独立pm配置)及灰度升级能力,广泛应用于金融、政务等需长期维护多代PHP应用的生产环境。本文聚焦CentOS 7平台

dixi7825的博客 368
上一篇: 链路层访问修改
下一篇: 双向链表实现线程池 用于TCP并发连接
七绝乌梭
博客等级 码龄18年 5粉丝 43原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值