守护进程也称精灵进程(Daemon):
是运行在后台的一种特殊进程。他独立与控制终端并且周期性的执行某种任务或者处理某些发生的事情。守护进程是一种很有用的进程,在操作系统中,维护系统各种设施的进程。
在Linux中,大多数服务器就是守护进程实现的:比如:Internet服务器inetd,Web服务器httpd
在上一篇博文例行性工作中。crond就是守护进程进行的任务。
系统服务进程不受用户注销登录的影响,只随系统关闭而关闭。
用ps axj命令查看系统中的进程。参数a表示不仅列当前用户的进程,也列出所有其他用户的进程,参数x表示不仅列有控制终端的进程,也列出所有无控制终端的进程,参数j表示列出与作业控制相关的信息。
下面我们来看一下系统中的守护进程:
凡是TPGID一栏写着-1的都是没有控制终端的进程,也就是守护进程。在COMMAND一列用[]括起来的 名字表示内核线程,这些线程在内核里创建,没有用户空间代码,因此没有程序文件名和命令行, 通常采用以k开头的名字,表示Kernel。init进程我们已经很熟悉了,udevd负责维护/dev目录下的 设备文件,acpid负责电源管理,syslogd负责维护/var/log下的日志文件,可以看出,守护进程通常采用以d结尾的名字,表示Daemon。
既然理解了守护进程的概念,那么我们来了解一下如何自己创建一个守护进程呢?
守护进程创建函数:
#include<unistd.h> pid_t setsid(void);
该函数调用成功时返回新创建的Session的id(其实也就是当前进程的id),出错返回-1。注意,调用这个函数之前,当前进程不允许是进程组的Leader,否则该函数返回-1。要保证当前进程不是进程组的Leader也很容易,只要先fork再调用setsid就行了。fork创建的子进程和父进程在同一个进程组中,进程组Leader必然是该组的第一个进程,所以子进程不可能是该组的第一个
进程,在子进程中调用setsid就不会有问题了。
成功调用该函数的结果是:
1. 创建一个新的Session,当前进程成为Session Leader,当前进程的id就是Session的id。
2. 创建一个新的进程组,当前进程成为进程组的Leader,当前进程的id就是进程组的id。
3. 如果当前进程原本有一个控制终端,则它失去这个控制终端,成为一个没有控制终端的进
程。所谓失去控制终端是指,原来的控制终端仍然是打开的,仍然可以读写,但只是一个普
通的打开文件而不是控制终端了。
创建守护进程
1. 调用umask将文件模式创建屏蔽字设置为0.
2. 调用fork,父进程退出(exit)。原因:1)如果该守护进程是作为一条简单的shell命令
启动的,那么父进程终止使得shell认为该命令已经执行完毕。2)保证子进程不是一个
进程组的组长进程。
3. 调用setsid创建一个新会话。setsid会导致:1)调用进程成为新会话的首进程。 2)调用
进程成为一个进程组的组长进程 。3)调用进程没有控制终端。(再次fork一次,保证
daemon进程,之后不会打开tty设备)
4. 将当前工作目录更改为根目录。
5. 关闭不在需要的文件描述符。
6. 其他:忽略SIGCHLD信号。
下面我们来自己创建一个守护进程:
#include<stdio.h> #include<signal.h> #include<unistd.h> #include<stdlib.h> #include<fcntl.h> #include<sys/stat.h> void creat_deamon() { int i ; int fd0; pid_t pid; struct sigaction sa; umask(0); if((pid = fork()) < 0) { printf("fork error"); } else if(pid != 0) { exit(0); } setsid(); sa.sa_handler = SIG_IGN; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; if(sigaction(SIGCHLD,&sa,NULL) < 0) { return ; } if((pid = fork()) < 0) { printf("fork error to child"); return; } else if(pid != 0) { exit(0); } if(chdir("/") < 0) { printf("child dir error"); return; } close(0); fd0 = open("dev/null",O_RDWR); dup2(fd0,1); dup2(fd0,2); } int main() { creat_deamon(); while(1) { sleep(1); } return 0; }
运行结果:
其实对于创建守护进程而言,我们需要做的是:
(1)在父进程中执行fork并exit推出;
(2)在子进程中调用setsid函数创建新的会话;
(3)在子进程中调用chdir函数,让根目录 ”/” 成为子进程的工作目录;
(4)在子进程中调用umask函数,设置进程的umask为0;
(5)在子进程中关闭任何不需要的文件描述符
好了守护进程就是跟随着操作系统一直在运行,知道操作系统关闭时结束的进程,在操作系统中大多数进程任务就是守护进程,在开始的时候就进行启动控制操作系统监视的。