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

时间:2021-12-19 18:26:18

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


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




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


static intnchildren;
static pid_t*pids;


int
main(int argc, char **argv)
{
intlistenfd, i;
socklen_taddrlen;
voidsig_int(int);
pid_tchild_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)
{
inti;
voidpr_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_tpid;
voidchild_main(int, int, int);


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


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