守护进程又称精灵进程(daemon):是运行在后台的一种特殊进程;它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。
守护进程的特点:
1、自成一个会话;
2、没有控制终端,不能直接和用户交互;
3、一直在运行着,不受用户登录和注销的影响。
Linux系统启动时会启动很多系统服务进程;用ps axj命令查看系统中的进程,在COMMAND一列用[]括起来的名字表示内核线程,这些线程在内核里创建,没有用户空间代码,因此没有程序文件名和命令行, 通常采用以k开头的名字,表示Kernel。tty为?或TPGID为-1的通常为守护进程。例如:udevd负责维护/dev目录下的设备文件;acpid负责电源管理;syslogd负责维护/var/log下的日志文件。可以看出守护进程通常采用以d结尾的名字,表示Daemon。
pid_t setsid(void) //创建一个新的会话,并成为会话首进程
该函数调用成功时返回新创建的会话的id(其实也就是当前进程的id),出错返回-1。注意:调用这个函数之前,当前进程不允许是进程组的组长进程,否则该函数返回-1。
成功调用该函数的结果是:
1、创建一个新的会话,当前进程成为会话组长,当前进程的id就是会话的id。
2、创建一个新的进程组,当前进程成为进程组的组长,当前进程的id就是进程组的id。
3、如果当前进程原本有一个控制终端,则它失去这个控制终端,成为一个没有控制终端的进程。所谓失去控制终端是指原来的控制终端仍然是打开的,仍然可以读写,但只是一个普通的打开文件而不是控制终端了。
创建一个守护进程:
1、调用umask()将文件模式创建屏蔽字设置为0。
2、调用fork(),且父进程退出。原因:如果该守护进程是作为一条简单的shell命令启动的,那么父进程终止使得shell认为该命令已经执行完毕。保证子进程不是一个进程组的组长进程。
3、调用setsid()创建一个新会话。
4、fork()创建第二子进程,然后结束第一子进程。防止无控制终端且为会话组长的守护进程申请打开控制终端。
5、 将当前工作目录更改为根目录。
6、关闭不再需要的文件描述符。
7、忽略SIGCHLD信号。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <stdlib.h>
void mydaemon()
{
umask(0);
pid_t id = fork();//创建第一子进程
if(id>0){//father
exit(0);
}
//child 第一子进程成为新建会话的会话组长
printf("%d\n",getpid());
setsid();
if((id = fork())>0)//创建第二子进程,结束第一子进程,第二子进程不是会话首进程,不会与其他终端关联
{
exit(0);
}
chdir("/");// 将当前工作目录更改为根目录
close(0);//关闭不需要的文件描述符
close(1);
close(2);
signal(SIGCHLD,SIG_IGN);
}
int main()
{
mydaemon();
while(1);
return 0;
}
使用库函数来创建守护进程:
int daemon(int nochdir,int noclose)//创建一个守护进程
参数一:nochdir为0时,当前目录变为根目录,否则不变。
参数二:noclose为0时,文件描述符重定向至/dev/null即不输入任何信息,否则输出。
返回值:deamon()调用了fork(),如果fork成功,那么父进程就调用_exit(2)退出,所以看到的错误信息全部是子进程产生的。如果成功函数返回0,否则返回-1并设置errno。