Linux环境编程之进程(七):守护进程
守护进程也是一种进程,它由例如以下特性:
1、生存期较长,在系统自举时启动,仅在系统关闭时终止。
2、没有控制终端,在后台执行。
系统中有非常多守护进程,它们执行日常事务活动。
如日志进程syslogd、webserverhttpd、邮件serversendmail和数据块servermysqld等。大多数守护进程都是以超级用户(用户ID为0)特权执行。没有一个守护进程具有控制终端,其终端设置为问号(?),终端前台进程组ID设置为-1。内核守护进程以无控制终端方式启动。用户层守护进程缺少控制终端可能是守护进程调用了setsid的结果。
全部用户层守护进程都是进程组长进程以及会话的首进程,并且是这些进程组和会话中的唯一进程。最后,大多数守护进程的父进程是init进程。
(一)编程规则
1、调用umask将文件模式创建屏蔽字设置为0。
2、调用fork,然后使父进程退出(exit)。
3、调用setsid以创建一个新会话。
使调用进程:a、成为新会话的首进程。b、成为一个新进程组的组长进程。c、没有控制终端。
4、将当前工作文件夹更改为根文件夹。
5、关闭不须要的文件描写叙述符。
6、某些守护进程打开/dev/null使其具有文件描写叙述符0、1和2。
(二)出错记录
由于守护进程没有控制终端,所以不能仅仅是简单地写到标准出错上。
那么该怎样处理出错消息呢?我们不希望全部守护进程都写到控制台设备上,也不希望每一个守护进程将它自己的出错消息写到一个单独的文件里,由于要关心哪一个守护进程写到哪一个记录文件里。并定期地检查这些文件,会非常麻烦。所以,须要有一个集中的守护进程出错记录设施。
如上图所看到的,有3种方法产生日志消息:
1、内核例程能够调用log函数。
不论什么一个用户进程通过打开(open)然后读(read)/dev/klog设备就能够读取这些消息。
2、大多数用户进程(守护进程)调用syslog函数以产生日志消息。
//以下给出样例
3、在此主机上的一个用户进程。或通过TCP/IP网络连接到此主机的其它主机上的一个用户进程可将日志消息发向UDPport514。
#include <syslog.h>
void openlog(const char *ident, int option, int facility);
void syslog(int priority, const char *format, ...);
void closelog(void);
參数:
identity通常是程序的名称。
option參数是指定很多选项的位屏蔽。
priority參数是facility和level的组合。
(三)演示样例程序
/* *File Name : daemo.c *Autho : libing *Mail : libing1209@126.com */ #include "stdio.h" #include "stdlib.h" #include <syslog.h> #include <fcntl.h> #include <signal.h> #include <sys/resource.h> int daemonize(void) { int i, fd0, fd1, fd2; pid_t pid; struct rlimit rl; /* *调用umask将文件模式创建屏蔽字设置为0 */ umask(0); /* *调用fork,然后使父进程退出(exit) */ if((pid = fork()) < 0){ printf("can't fork."); return -1; } else if(pid != 0) /*parent*/ exit(0); setsid();//调用setsid以创建一个新会话 /* *将当前工作文件夹更改为根文件夹 */ if(chdir("/") < 0) printf("can't change directory to/"); /* *Get maximum number of file descriptors. */ if(getrlimit(RLIMIT_NOFILE, &rl) < 0) printf("can't get file limit.\n"); /* *关闭不须要的文件描写叙述符. */ if(rl.rlim_max == RLIM_INFINITY) rl.rlim_max = 1024; for(i = 0; i < rl.rlim_max; i++) close(i); /* *守护进程打开/dev/null使其具有文件描写叙述符0、1和2。 */ fd0 = open("/dev/null", O_RDWR); fd1 = dup(0); fd2 = dup(0); return 0; } int main(void) { daemonize(); openlog("daemotest", LOG_PID, LOG_USER); syslog(LOG_INFO, "program started."); while(1){ sleep(1); } return 0; }
执行測试结果:
编译:gcc daemo.c -o daemotest 执行:./daemotest 測试:ps axj | grep daemotest 1 6565 6565 6565 ? -1 Ss 1000 0:00 ./daemotest能够看出daemotest进程的父进程是1。没有终端控制(TTY选项为“?”)。其记录在/var/log/messages文件里,能够在该文件里找到"program started"字样的记录。