摘要:
在之前的《服务器编程入门(5)Linux服务器程序规范》中,我们提到过将服务器程序后台化,这就是本节将要讨论的守护进程.
本节主要关注一下问题:
1 什么是守护进程?
2 守护进程的启动方法有哪些?
3 如何创建一个守护进程?
在后台运行,且不与任何控制终端关联的进程。
守护进程不与作业控制、终端会话管理、终端产生信号等发生交互,也可以避免在后台运行的守护进程非预期地输出到终端。
两个特点:
在理解更多关于守护进程的概念之前,我们先了解一下进程、进程组、会话期和控制终端的关系。
守护进程与普通进程的区别如下图所示:
首先我们使用库函数daemon创建守护进程,然后研究一下守护进程的创建过程,并实现一个守护进程化函数,达到和库函数daemon相同的效果。
函数:daemon
声明:
#include <unistd.h> int daemon(int nochdir, int noclose);
作用:通过在服务器程序中调用它,可以把一个普通进程转变为守护进程。
参数说明:
If nochdir is zero, daemon() changes the process’s current working directory to the root directory ("/"); otherwise,
If noclose is zero, daemon() redirects standard input, standard output and standard error to /dev/null; otherwise, no changes are made to these file descriptors.
Demo:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <time.h> #include <fcntl.h> #include <string.h> #include <error.h> int main(int argc, char* argv[]) { time_t t; int fd; // 将当前进程变成守护进程 if (daemon(0, 0) == -1) { perror("daomon error"); exit(EXIT_FAILURE); } while(1) { //这时工作目录已经被daemon函数切换到了系统根目录下 fd = open("daemon.log", O_WRONLY|O_CREAT|O_APPEND, 0644); if (fd == -1) { perror("open daemon.log error"); exit(EXIT_FAILURE); } t = time(0); char *buf = asctime(localtime(&t)); write(fd, buf, strlen(buf)); //向daemon.log文件中写入当前时间 close(fd); sleep(60); // 每隔60s写入一次 } }
运行截图:
执行ps命令发现,并没有名为testDaemon的守护进程,主要原因是daemon函数会将当前工作目录切换到/目录下,而普通用户没有权限在系统根目录创建文件。
所以实际上出错在fd = open("daemon.log", O_WRONLY|O_CREAT|O_APPEND, 0644); 这里,又因为守护进程是不和当前终端交互的,所以没有看到报错信息。
现在我们切换到root用户执行程序,运行截图:
守护进程创建过程:
代码实现:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <time.h> #include <fcntl.h> #include <string.h> #include <error.h> #include <signal.h> #define MAXFD 64 extern int daemon_proc; int myDaemon(int ,int ); int main(int argc, char* argv[]) { time_t t; int fd; if (myDaemon(0, 0) == -1) { perror("daomon error"); exit(EXIT_FAILURE); } while(1) { fd = open("daemon.log", O_WRONLY|O_CREAT|O_APPEND, 0644); if (fd == -1) { perror("open daemon.log error"); exit(EXIT_FAILURE); } t = time(0); char *buf = asctime(localtime(&t)); write(fd, buf, strlen(buf)); close(fd); sleep(60); } fprintf(stderr, "Hello world!\n"); } int myDaemon(int nochdir, int noclose) { int i; pid_t pid; if ( (pid = fork()) < 0 ) return -1; else if (pid) { /* parent terminated */ _exit(0); } /* child 1 continues... */ if (setsid() < 0) /* become session leader */ return -1; signal(SIGHUP, SIG_IGN); /* ignore SIGHUP singal */ if ( (pid = fork()) < 0 ) return -1; else if (pid) { _exit(0); /* child 1 terminated */ } /* child 2 continues... */ daemon_proc = 1; /* use syslog instead of fprintf to stderr */ if (nochdir == 0) chdir("/"); /* change working directory */ if (noclose == 0) { /*close off file descriptors*/ for (i = 0; i < MAXFD; i++) close(i); /* redirect stdin, stdout, and stderr to /dev/null */ open("/dev/null", O_RDONLY); open("/dev/null", O_RDWR); open("/dev/null", O_RDWR); } umask(0); }
运行截图:
参考资料:
《UNIX网络编程 卷1:套接字联网API(第3版)》
服务器编程入门(12) 守护进程,布布扣,bubuko.com
原文:http://www.cnblogs.com/suzhou/p/daemon.html