守护进程是Linux中的后台服务进程,一般都是在后台运行的,它的生存期比较长。一般都是系统自举时启动,系统关闭时终止。
在Linux中,有一个系统与用户交互的界面,成为终端,很多进程的启动和停止都与终端有很大的关系,一般我们在Linux下编写的代码都是在终端下执行或者停止的,但是守护进程突破了这种限制,它从被执行的时候开始运转,直到系统关闭时才结束,用这种方法,可以为我们的系统提供多种服务,所以是十分重要的。
要编写一个守护进程一定要掌握守护进程的编程规则,以免出现一些不需要的交互作用,这里交互作用的意思个人理解就是一个多个守护进程或进程之间存在一定的关系,从而在执行的时候影响到其他进程,应该理解是:每个守护进程之间都是透明的。
规则:
1. 调用umask将文件模式创建屏蔽字设为0. 理由:继承的文件模式有可能有所限制,导致某些读写权限的不可访问
2. 调用fork,然后是父进程退出。理由:实际上是做到了进程与终端的脱离,父进程执行后被关闭,子进程后台运行。
3. 在子进程里创建一个新的会话。调用函数为setsid。理由:守护进程需要完全脱离父进程的关系,包括进程组和会话的控制,个人理解就是子进程完全自立门户的一个过程。
4. 将工作目录更改为根目录。理由:父进程工作目录在进程运行中是不能卸载的,修改工作目录的目的是为了守护进程在其他目录下也能更好的工作,避免不必要的麻烦
5. 关闭不需要的文件描述符。理解:子进程继承到了父进程的文件描述符,当然这些是多余的,为了节省资源,关闭。
守护进程的出错记录
守护进程不像普通程序,在调试的时候可以使用gdb或是在编译的时候出现在终端上的报错原因和行号,所以在编写守护进程的时候出错处理就变得十分重要。
所以守护进程就有它自己的出错记录方式,一般有三种方式产生出错日志:
1. 内核例程可以调用log函数,但是这一方式牵涉到内核,暂不研究
2. 调用syslog函数产生日志消息,这个是我们要掌握的
3. 通过TCP/IP链接的进程可以将日志消息发送到UDP端口514,需要网络编程,也不讨论
关于第二种方式的讨论
Syslog是Linux中的系统日志管理服务,该机制决定的不同种类的信息发向何处,比如紧急消息就发送给系统管理员并在控制台显示,警告消息则发送到一个记录文件中。该机制提供了3个函数接口,分别是openlog,syslog和closelog.
关于理论方面也就这些,用代码来实现一个守护进程的例程才是方便理解的
代码中先建立起来一个守护进程,然后再该守护进程中建立一个子进程,该子进程先暂停10S然后自动退出,并且由守护进程收集其子进程的退出消息。其中子进程和守护进程的退出消息都在/var/log/message中输出。子进程退出后,守护进程循环停止,其时间间隔为10S。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> #include <sys/wait.h> #include <syslog.h> #define MAXFILE 65535 int create_daemon() { int i ; setsid(); chdir("/"); umask(0); for(i = 0 ;i < MAXFILE ; i++){ close (i); } } int main(int argc , char **argv) { pid_t child1,child2; child1 = fork(); if(child1 < 0 ) perror("fork error"); else if(child1 > 0) exit(1); create_daemon(); child2 = fork(); if(child2 < 0) perror("fork error"); else if(child2 == 0){ syslog(LOG_INFO,"child2 will sleep for 10s"); sleep(10); syslog(LOG_INFO , "child2 will exit"); exit(0); } else{ waitpid(child2,NULL,0); syslog(LOG_INFO,"child1 noticed that child2 has exited"); closelog(); while(1){ sleep(10); } } return 0; } |
编译 运行 进程查看
[root@localhost daemon]# gcc daemon.c
[root@localhost daemon]# ./a.out
[root@localhost daemon]# ps -ef|grep a.out
root 1322 1 0 10:31 ? 00:00:00 ./a.out
root 1339 2790 0 10:31 pts/1 00:00:00 grep a.out
[root@localhost daemon]# cat /var/log/messages
Apr 27 10:31:27 localhost a.out: child2 will sleep for 10s
Apr 27 10:31:37 localhost a.out: child2 will exit
Apr 27 10:31:37 localhost a.out: child1 noticed that child2 has exited
参考书籍 《UNIX环境高级编程》 《嵌入式Linux应用程序开发详解》
发表评论
要发表评论,您必须先登录。