UNP学习笔记(第十三章 守护进程和inetd超级服务器)

关于守护进程可以查看apue的笔记 http://www.cnblogs.com/runnyu/p/4645046.html

 

 

daemon_init函数

下面给出名为daemon_init函数,通过调用它(通常从服务器程序中),我们能够把一个普通进程转变为守护进程

 1 #include    "unp.h"
 2 #include    <syslog.h>
 3 
 4 #define    MAXFD    64
 5 
 6 extern int    daemon_proc;    /* defined in error.c */
 7 
 8 int
 9 daemon_init(const char *pname, int facility)
10 {
11     int        i;
12     pid_t    pid;
13 
14     if ( (pid = Fork()) < 0)
15         return (-1);
16     else if (pid)
17         _exit(0);            /* parent terminates */
18 
19     /* child 1 continues... */
20 
21     if (setsid() < 0)            /* become session leader */
22         return (-1);
23 
24     Signal(SIGHUP, SIG_IGN);
25     if ( (pid = Fork()) < 0)
26         return (-1);
27     else if (pid)
28         _exit(0);            /* child 1 terminates */
29 
30     /* child 2 continues... */
31 
32     daemon_proc = 1;            /* for err_XXX() functions */
33 
34     chdir("/");                /* change working directory */
35 
36     /* close off file descriptors */
37     for (i = 0; i < MAXFD; i++)
38         close(i);
39 
40     /* redirect stdin, stdout, and stderr to /dev/null */
41     open("/dev/null", O_RDONLY);
42     open("/dev/null", O_RDWR);
43     open("/dev/null", O_RDWR);
44 
45     openlog(pname, LOG_PID, facility);
46 
47     return (0);                /* success */
48 }
View Code

作为守护进程运行的时间获取服务器程序

 1 #include    "unp.h"
 2 #include    <time.h>
 3 
 4 int
 5 main(int argc, char **argv)
 6 {
 7     int listenfd, connfd;
 8     socklen_t addrlen, len;
 9     struct sockaddr    *cliaddr;
10     char buff[MAXLINE];
11     time_t ticks;
12 
13     if (argc < 2 || argc > 3)
14         err_quit("usage: daytimetcpsrv2 [ <host> ] <service or port>");
15 
16     daemon_init(argv[0], 0);
17 
18     if (argc == 2)
19         listenfd = Tcp_listen(NULL, argv[1], &addrlen);
20     else
21         listenfd = Tcp_listen(argv[1], argv[2], &addrlen);
22 
23     cliaddr = Malloc(addrlen);
24 
25     for ( ; ; ) {
26         len = addrlen;
27         connfd = Accept(listenfd, cliaddr, &len);
28         err_msg("connection from %s", Sock_ntop(cliaddr, len));
29 
30         ticks = time(NULL);
31         snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
32         Write(connfd, buff, strlen(buff));
33 
34         Close(connfd);
35     }
36 }
View Code

 

 

 

inetd守护进程

典型的UNIX系统可能存在许多服务器,它们只是等待客户请求的到达,例如:FTP、Telnet、Rlogin、TFTP等等。

在之前,所有这些服务都有一个进程与之关联,而且每个进程执行几乎相同的启动任务。这个模型存在以下两个问题:

1.所有这些守护进程含有几乎相同的启动代码。

2.每个守护进程在进程表中占据一个表项,然后它们大部分时间处于睡眠状态。

4.3BSD版本基于TCP或UDP的服务器都可以使用inetd守护进程来解决上述两个问题:

1.通过由inetd处理普通守护进程的大部分启动细节以简化守护进程的编写。

2.单个进程(inetd)就能为多个服务等待外来的客户请求,以此取代每个服务一个进程的做法。

inetd进程使用我们随daemon_init函数讲解的技巧把自己演变成一个守护进程。

接着读入并处理自己的配置文件。通常是/etc/inetd.conf的配置文件制定本超级服务器处理哪些服务以及当一个服务请求到达时该怎么做。该文件中每行包含的字段如下图所示:

下面是inetd.conf文件中作为例子的若干行:

下面展示inetd守护进程的工作流程

 

1.在启动阶段,读入/etc/inetd.conf文件并给该文件中指定的每个服务创建一个适当类型的套接字。新创建的每个套接字都被加入到将由某个select调用使用的一个描述符。

2.位每个套接字调用bind,指定捆绑相应服务器的总所周知的端口和通配地址。端口号通过getservbyname获得。

3.对于每个TCP套接字,调用listen以接收外来的连接请求。对于UDP套接字则不执行该步骤。

4.创建完毕所有套接字之后,调用select等待其中任何一个套接字变为可读。

5.当select返回指出某个套接字可读之后,如果该套接字时一个TCP套接字,而且其服务器的wait-flag值为nowait,那么调用accept接受这个新连接。

6.inetd守护进程调用fork派生进程,并由子进程处理服务请求。(子进程首先与终端脱离,然后调用exec执行相应的server-program字段指定的程序来具体处理请求)

7.如果第五步中select返回的是一个字节流套接字,那么父进程必须关闭已连接套接字(就像标准并发服务器那样)。父进程再次调用select,等待下一个变为可读的套接字。

 

 

 

daemon_inetd函数

下面给出一个名为daemon_inetd的函数,可用于已知由inetd启动的服务器程序中。

 1 #include    "unp.h"
 2 #include    <syslog.h>
 3 
 4 extern int    daemon_proc;    /* defined in error.c */
 5 
 6 void
 7 daemon_inetd(const char *pname, int facility)
 8 {
 9     daemon_proc = 1;        /* for our err_XXX() functions */
10     openlog(pname, LOG_PID, facility);
11 }
View Code

与daemon_init相比,所有的守护进程化步骤已由inetd在启动时执行。本函数的任务仅仅是为错误处理函数设置daemon_proc标志,并调用openlog

下面给出由inetd作为守护进程启动的时间获取服务器程序

 1 #include    "unp.h"
 2 #include    <time.h>
 3 
 4 int
 5 main(int argc, char **argv)
 6 {
 7     socklen_t        len;
 8     struct sockaddr    *cliaddr;
 9     char            buff[MAXLINE];
10     time_t            ticks;
11 
12     daemon_inetd(argv[0], 0);
13 
14     cliaddr = Malloc(sizeof(struct sockaddr_storage));
15     len = sizeof(struct sockaddr_storage);
16     Getpeername(0, cliaddr, &len);
17     err_msg("connection from %s", Sock_ntop(cliaddr, len));
18 
19     ticks = time(NULL);
20     snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
21     Write(0, buff, strlen(buff));
22 
23     Close(0);    /* close TCP connection */
24     exit(0);
25 }
View Code

可以看到,所有套接字创建代码都消失了。这些步骤改由inetd执行。

为了运行本例子的程序,我们首先赋予本服务一个名字和端口,将如下行加到/etc/services文件中:

mydaytime     9999/tcp

接着把如下行加到/etc/inetd.conf文件中:

mydaytime stream tcp nowait andy /home/andy/daytimetcpsrv3 daytimetcpsrv3

然后给inetd发送一个SIGHUP信号,告知它重新读入其配置文件。

接着我们执行netstat命令验证inetd已在TCP端口9999上创建一个监听套接字

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值