1.让进程在后台执行。方法是调用fork产生一个子进程,然后使得父进程退出。
2.调用setsid创建一个新会话。控制终端,登录会话和进程组通常是从父进程继承下来的,守护进程要摆脱它们,不受它们影响,其方法是调用setsid使进程成为一个会话组长。
Linux中的进程与控制终端,登录会话和进程组之间的关系:进程属于一个进程组,进程组号(GID)就是进程组长的进程号(PID)。登录会话可以包含多个进程组。这些进程组共享一个控制终端。这个控制终端通常是创建进程的登录终端。控制端,登录会话和进程组通常是从父进程继承下来的。我们的目的就是要摆脱它们,使之不受它们的影响。方法是在第1点的基础上,调用setsid()使进程成为会话组长:setsid();
说明:当进程是会话组长时setsid()调用失败。但第一点已经保证进程不是会话组长。setsid()调用成功后,进程成为新的会话组长和新的进程组长,并与原来的登录会话和进程组脱离。由于会话过程对控制终端的独占性,进程同时与控制终端脱离。
如果,调用setsid的进程不是一个进程组的组长,此函数创建一个新的会话期。
(1)此进程变成该对话期的首进程
(2)此进程变成一个新进程组的组长进程。
(3)此进程没有控制终端,如果在调用setsid前,该进程有控制终端,那么与该终端的联系被解除。如果该进程是一个进程组的组长,此函数返回错误。
(4)为了保证这一点,我们先调用fork()然后exit(),此时只有子进程在运行。
编写守护进程的一般步骤步骤:
(1)在父进程中执行fork并exit退出;
(2)在子进程中调用setsid函数创建新的会话;
(3)在子进程中调用chdir函数,让根目录 ”/” 成为子进程的工作目录;
(4)在子进程中调用umask函数,设置进程的umask为0;
(5)在子进程中关闭任何不需要的文件描述符
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <stdlib.h>
int init_daemon(void)
{
int pid;
int i;
signal(SIGTTOU, SIG_IGN);
signal(SIGTTIN, SIG_IGN);
signal(SIGTSTP, SIG_IGN);
signal(SIGHUP, SIG_IGN);
pid = fork();
if(pid > 0)
exit(0);
else if(pid == -1)
return -1;
setsid();
pid = fork();
if(pid > 0)
exit(1);
else if(pid == -1)
return -1;
for(i = 0; i < NOFILE; close(i++))
;
chdir("/");
umask(0);
signal(SIGCHLD, SIG_IGN);
return 0;
}
int main(void)
{
time_t now;
init_daemon();
while(1)
{
sleep(8);
time(&now);
printf("系统时间:\t%s\t\t\t\n", ctime(&now));
}
return 0;
}