1、调用函数fork()创建子进程,然后父进程终止,保留子进程继续运行。之所以要让父进程终止是因为,当一个进程是以前台进程方式由shell启动时,在父进程终止之后子进程自动转为后台进程。另外,我们在下一步要创建一个新的会话期,这就要求创建会话期的进程不是一个进程组的组长进程。当父进程终止,子进程运行,这就保证了进程组的组ID与子进程的进程ID不会相等。
或者
使用 setsid 设置为新会话的领头进程,因为 setsid 要求调用进程不是会话的领头进程时才有效。因此, 首先可用 fork 派生, 并结束父进程。之后调用 setsid, 子进程成为新会话的领头进程, 从而与原有会话, 进程组, tty 脱离。但是, 为避免作为新会话领头进程的子进程在打开一个终端设备时, 拥有一个控制终端,再次派生, 并结束父进程, 可让子进程成为非会话领头进程。
if (fork ()) //创建子进程
exit (0); //结束父进程
setsid (); //建立新的会话组
if (fork ()) //创建孙进程
exit (0); //结束子进程
2、信号处理,包括处理 SIGCHLD 信号, 为避免形成僵尸进程。
3、关闭不再需要的文件描述符,并为标准输入、标准输出和标准错误输出打开新的文件描述符(也可以继承父进程的标准输入、标准输出和标准错误输出文件描述符,这个操作是可选的)。
4、调用函数chdir("/")将当前工作目录更改为根目录。这是为了保证我们的进程不使用任何目录。否则我们的守护进程将一直占用某个目录,这可能会造成超级用户不能卸载一个文件系统。
5、调用函数umask(0)将文件方式创建屏蔽字设置为"0"。这是因为由继承得来的文件创建方式屏蔽字可能会禁止某些许可权。例如我们的守护进程需要创建一组可读可写的文件,而此守护进程从父进程那里继承来的文件创建方式屏蔽字却有可能屏蔽掉了这两种许可权,则新创建的一组文件其读或写操作就不能生效。因此要将文件方式创建屏蔽字设置为"0"。
下面是一段完整的守护进程的代码:
#include <stdio.h>;
#include <fcntl.h>;
#include <signal.h>;
#include <unistd.h>
#define RUNNING_DIR "/tmp"
#define LOCK_FILE "exampled.lock"
#define LOG_FILE "exampled.log"
void log_message(filename,message)
{
char *filename;
char *message;
{
FILE *logfile;
logfile=fopen(filename,"a");
if(!logfile) return;
fprintf(logfile,"%s/n",message);
fclose(logfile);
}
}
void signal_handler(sig)
{
int sig;
{
switch(sig)
{
case SIGHUP:
log_message(LOG_FILE,"hangup signal catched");
break;
case SIGTERM:
log_message(LOG_FILE,"terminate signal catched");
exit(0);
break;
}
}
}
void daemonize()
{
int i,lfp;
char str[10];
if(getppid()==1) return; /* already a daemon */
i=fork();
if(i<0) exit(1); /* fork error */
if(i>0) exit(0); /* parent exits */
/* child (daemon) continues */
setsid(); /* obtain a new process group */
for (i=getdtablesize();i>=0;--i) close(i); /* close all descriptors */
i=open("/dev/null",O_RDWR); dup(i); dup(i); /* handle standart I/O */
umask(027); /* set newly created file permissions */
chdir(RUNNING_DIR); /* change running directory */
lfp=open(LOCK_FILE,O_RDWR|O_CREAT,0640);
if (lfp<0) exit(1); /* can not open */
if (lockf(lfp,F_TLOCK,0)<0) exit(0);/*can not lock */
/* first instance continues */
sprintf(str,"%d/n",getpid());
write(lfp,str,strlen(str));/*record pid to lockfile*/
signal(SIGCHLD,SIG_IGN); /* ignore child */
signal(SIGTSTP,SIG_IGN); /* ignore tty signals */
signal(SIGTTOU,SIG_IGN);
signal(SIGTTIN,SIG_IGN);
signal(SIGHUP,signal_handler); /* catch hangup signal */
signal(SIGTERM,signal_handler); /* catch kill signal */
}
main()
{
daemonize();
while(1) sleep(1); /* run */
}
1、编译cc -o exampled examped。c
2、运行。/exampled
3、测试daemon进程
ps -ef|grep exampled (or ps -aux on BSD systems)
4、log
tail -f /tmp/exampled.log
5、测试signal
kill -HUP `cat /tmp/exampled.lock`
6、终止
kill `cat /tmp/exampled.lock`