UNIX网络编程卷1 服务器程序设计范式2 预先派生子进程,每个子进程调用accept

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie


1.预先派生子进程:在启动阶段预先派生一定数量的子进程,当各个客户连接到达时,
这些子进程立即就能为它们服务。
2.优点是无须引入你进程执行 fork 的开销就能处理新到的客户。
缺点是父进程必须在服务器启动阶段猜测需要预先派生多少子进程。
3.父进程可以持续监视闲置子进程数,一旦该值降至低于某个阈值就派生额外的子进程,
一旦超另一个阈值就终止一些过剩的子进程。
4.如果有多个进程阻塞在引用同一个实体的描述符上,那么最好直接阻塞在诸如 accept 之类的函数而不是 select 之中。




/* include serv02 */
#include	"unp.h"


static int		nchildren;
static pid_t	*pids;


int
main(int argc, char **argv)
{
	int			listenfd, i;
	socklen_t	addrlen;
	void		sig_int(int);
	pid_t		child_make(int, int, int);


	//0.创建监听套接字
	if (argc == 3)
		listenfd = Tcp_listen(NULL, argv[1], &addrlen);
	else if (argc == 4)
		listenfd = Tcp_listen(argv[1], argv[2], &addrlen);
	else
		err_quit("usage: serv02 [ <host> ] <port#> <#children>");
	
	//1.增设一个命令行参数供用户指定预先派生的子进程个数。
	//分配一个存放各个子进程 ID 的数组,用于在父进程即将终止时由 main 函数终止所有子进程
	nchildren = atoi(argv[argc-1]);
	pids = Calloc(nchildren, sizeof(pid_t));


	//2.调用 child_make 创建各个子进程
	for (i = 0; i < nchildren; i++)
		pids[i] = child_make(i, listenfd, addrlen);	/* parent returns */


	//3.设置中断信号 SIGINT 的处理函数
	Signal(SIGINT, sig_int);


	//4.子进程负责处理所有事情。 --> ?? 为什么不直接 pause(),而要在 for 循环里 pause()
	for ( ; ; )
		pause();	/* everything done by children */
}
/* end serv02 */


// SIGINT 信号处理函数
/* include sigint */
void
sig_int(int signo)
{
	int		i;
	void	pr_cpu_time(void);


	//给每个子进程发送 SIGTERM 信号终止它们
	for (i = 0; i < nchildren; i++)
		kill(pids[i], SIGTERM);
	//用 wait 回收所有子进程的资源
	while (wait(NULL) > 0)		/* wait for all children */
		;
	if (errno != ECHILD)
		err_sys("wait error");


	//调用 pr_cpu_time 统计已终止子进程的资源利用统计
	pr_cpu_time();
	exit(0);
}
/* end sigint */


/* include child_make */
pid_t
child_make(int i, int listenfd, int addrlen)
{
	pid_t	pid;
	void	child_main(int, int, int);


	//调用 fork 派生子进程
	if ( (pid = Fork()) > 0)
		return(pid);		//父进程返回子进程的 pid 给 main 函数,回到 main 函数里的循环继续派生其它子进程


	child_main(i, listenfd, addrlen);	/* 子进程调用 child_main 函数,它是无限循环 */
}
/* end child_make */





你可能感兴趣的:(UNIX网络编程卷1 服务器程序设计范式2 预先派生子进程,每个子进程调用accept)