Hello,地球人们,Val今天来给大家分享一下关于守护进程的一些知识^_^
1. 守护进程是什么?
守护进程也叫精灵进程(Daemon),是运行在后台的一种特殊进程。她独立于终端并且周期性地执行某种人物或者等待某些发生的事件。
Linux的大多数服务器就是用守护进程实现的,例如:Internet服务器 inetd,Web服务器httped等。同时守护进程完成许多系统任务。如,作业规划进程crond等。
特点:不受用户登录注销等动作的影响。
2. 创建守护进程
创建守护进程最关键的一步是调用setsid函数创建一个新的会话(session),并成为话首进程(session leader)。
函数 pid_t setsid(void);
该函数创建成功时返回新创建的Session的id(当前进程的id),出错返回-1。fork()创建进程,然后让父进程退出exit,在子进程里调用setsid()。
成功调用该函数的结果是:
(1)创建一个新的会话(Session ),当前进程称为会话的话首进程,当前进程的id就是Session的id。
(2)创建一个新的进程组,当前进程成为进程组的组长进程,当前进程id就是进程组的id。
(3)如果当前进程原本有一个控制终端,则它失去这个控制终端,成为一个没有控制终端的进程。失去控制终端指,原来的控制终端仍是打开的,仍然可以读写,但只是一个普通的打开文件而不是控制终端了。
- 代码如何编写,关键步骤是哪些?
创建守护进程
*1.调用umask将文件模式创建屏蔽字设置为0
*2.调用fork,父进程exit。(如果该守护进程是作为一条简单的shell命令启动的,那么父进程终止使得shell认为该命令执行完毕;保证子进程不是一个进程组的组长进程)。
*3.调用setsid创建一个新会话。
setsid使调用进程成为新会话的首进程;
调用进程成为一个进程组的组长进程;
调用进程没有控制终端(再次fork一次,保证daemon进程之后不会打开tty设备)。
*4.当前工作目录改为根目录。
*5.关闭不需要的文件描述符。
*6.忽略SIGCHLD信号。
4.写一个daemon函数创建守护进程
代码如下:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
void creat_daemon(void)
{
int i;
int fd0;
pid_t pid;
struct sigaction sa;
umask(0); //设置文件掩码为0
if( (pid = fork()) < 0 )
{
}
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)
{ //再次fork,终止父进程,保持子进程不是话⾸进程,从而保证后续不会在和其他终端关联
printf("fork error!\n");
return;
}
else if( pid != 0)
{
exit(0);
}
if( chdir("/") < 0 )
{//更改工作目录到根
printf("child dir error\n");
return;
}
close(0);
fd0 = open("/dev/null", O_RDWR);
// 关闭标准输入,重定向所有标 准(输入输出错误)到/dev/null
dup2(fd0, 1);
dup2(fd0, 2);
}
int main()
{
creat_daemon();
while(1)
{
sleep(1);
}
}
运行结果如下图:(请原谅我图片里的错误的单词,其实应该是daemon我却写错了really,really sorry)
守护进程自成会话,自成进程组。
4.setsid()的作用是什么?
setsid()使得子进程成为会话组长(sid=pid),也是进程组组长(pgid==pid),并且脱离了原来的控制终端。所以,控制终端无论怎么操作,新的进程正常情况下不会收到它发来的信号。
5.umask(0)的作用:
子进程从父进程那里继承了一些东西,可能未把权限继承下来,所以要赋予它更高的权限,便于子进程操作。
6.chdir(“/”)作用:
进程活动时,其工作目录所在的文件系统不能卸下,一般需要将工作目录改变到根目录。
7.为什么创建守护进程时有人fork两次?
第一次fork为后面的setsid服务,setsid的调用者不能是进程组组长,而第一次调用的时候父进程是进程组组长。第二次调用后,把前面一次fork出来的子进程退出,这样第二次fork出来的子进程就和他们脱离了关系。其实第二次fork也不是必须的,也可以只fork一次,然后让父进程退出,子进程调用setsid,上面的代码例子就是后者。