⽤C语⾔在Linux系统下创建守护进程(Daemon)
守护进程(daemon)是指在后台运⾏的,没有控制终端与之相连的进程。它独⽴于控制终端,周期性地执⾏某种任务。Linux的⼤多数服务器就是⽤守护进程的⽅式实现的。如web服务器进程http等。守护进程在后台运⾏,类似于Windows中的系统服务。
编写守护进程程序的要点:
(1)让程序在后台执⾏。⽅法是调⽤fork()产⽣⼀个⼦进程,然后使⽗进程退出。
(2)调⽤setsid()创建⼀个新对话期。控制终端、登录会话和进程组通常是从⽗进程继承下来的,守护进程要摆脱它们,不受它们的影响,⽅法是调⽤setsid()使进程成为⼀个会话组长。setsid()调⽤成功后,进程成为新的会话组长和进程组长,并与原来的登录会话、进程组和控制终端脱离。
(3)禁⽌进程重新打开控制终端。经过以上步骤,进程已经成为⼀个⽆终端的会话组长,但是它可以重新申请打开⼀个终端。为了避免这种情况发⽣,可以通过使进程不再是会话组长来实现。再⼀次通过fork()创建新的⼦进程,使调⽤fork的进程退出。
(4)关闭不再需要的⽂件描述符。⼦进程从⽗进程继承打开的⽂件描述符。如不关闭,将会浪费系统资源,造成进程所在的⽂件系统⽆法卸下以及引起⽆法预料的错误。⾸先获得最⾼⽂件描述符值,然后⽤
⼀个循环程序,关闭0到最⾼⽂件描述符值的所有⽂件描述符。
(5)将当前⽬录更改为根⽬录。
(6)⼦进程从⽗进程继承的⽂件创建屏蔽字可能会拒绝某些许可权。为防⽌这⼀点,使⽤unmask(0)将屏蔽字清零。
(7)处理SIGCHLD信号。对于服务器进程,在请求到来时往往⽣成⼦进程处理请求。如果⽗进程不等待⼦进程结束,⼦进程将成为僵⼫进程(zombie),从⽽占⽤系统资源。如果⽗进程等待⼦进程结束,将增加⽗进程的负担,影响服务器进程的并发性能。在Linux下可以简单地将SIGCHLD信号的操作设为SIG_IGN。这样,⼦进程结束时不会产⽣僵⼫进程。
守护进程的实例:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <time.h>
#include <syslog.h>
int init_daemon(void)
{
int pid;
int i;
//忽略终端I/O信号,STOP信号
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 < 0) {
return -1;
}
//建⽴⼀个新的进程组,在这个新的进程组中,⼦进程成为这个进程组的⾸进程,以使该进程脱离所有终端
/
/建⽴⼀个新的进程组,在这个新的进程组中,⼦进程成为这个进程组的⾸进程,以使该进程脱离所有终端 setsid();
//再次新建⼀个⼦进程,退出⽗进程,保证该进程不是进程组长,同时让该进程⽆法再打开⼀个新的终端 pid=fork();
if( pid > 0) {
exit(0);
}
else if( pid< 0) {
return -1;
}
//关闭所有从⽗进程继承的不再需要的⽂件描述符
for(i=0;i< NOFILE;close(i++));
//改变⼯作⽬录,使得进程不与任何⽂件系统联系
chdir("/");
//将⽂件当时创建屏蔽字设置为0
umask(0);
//忽略SIGCHLD信号
signal(SIGCHLD,SIG_IGN);
return 0;
}
int main()
{
time_t now;
init_daemon();
syslog(LOG_USER|LOG_INFO,"TestDaemonProcess! \n");
while(1) {
sleep(8);
time(&now);
syslog(LOG_USER|LOG_INFO,"SystemTime: \t%s\t\t\n",ctime(&now));
}
}
编译运⾏上述程序。然后⽤ps -ef 命令查看进程状态,该进程状态如下:
从结果可以看出该进程具备守护进程的所有特征。
查看/var/log⽬录下,先前并不存在的test.log⽂件已经有了。
linux下的sleep函数
⽤vi打开该⽇志⽂件,记录如下:
最后需要关闭此守护进程。关闭的⽅法是通过ps -ef命令查询到该进程的进程号,之后再⽤kill 命令将其杀死。
注意:使⽤syslog函数前需要配置。但需要注意的是,在Centos6.x系统中,系统⽇志的配置⽂件已经发⽣了变化。不再是原来的/f了,⽽是/f。打开上述⽂件,在⽂件末尾加⼊下⾯⼀⾏:
user.*    /var/log/test.log
然后重启syslog服务。重启的命令也修改为:/etc/init.d/rsyslog restart
实际上,Linux提供了完成上述同样功能的库函数:
#include <unistd.h>
int daemon(int nochdir,int noclose);
其中,nochdir参数⽤于指定是否改变⼯作⽬录,如果给它传递0,则⼯作⽬录将被设置为“/”(根⽬录),否则继续使⽤当前⼯作⽬录。noclose参数为0时,标准输⼊、标准输出和标准错误输出都被重定向到/dev/null⽂件,否则依然使⽤原来的设备。该函数成功时返回0,失败返回-1,并设置errno。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。