设置精灵进程
static void set_daemon(void)
{
pit_t pid;
int fd;
pid = fork();
if(pid < 0)
{
log_error("Set daemon error!);
exit(-1);
}
else if( pid > 0)
{
exit(0);
}
fd = open("/dev/null".O_RDWR);
/* we want close stdin stdou*/
{
close(0);
close(1);
dup(fd);
dup(fd);
close(fd);
}
setsid();
pid = fork();
if( pid<0)
{
log_error("Set: daemon error");
exit(-1);
}
else if(pid > 0)
{
exit(0);
}
}
其中,最重要的一个函数调用是setsid,目的是创建一个新对话期。使调用进程:
(a)成为新对话期的首进程
(b)成为一个新进程组的首进程
(c)没有控制终端
这里面有三个概念:进程组、会话期与控制终端,下面分别阐述。
进程组:
进程组的概念是因管道符而生。
用管道符连接的进程都在同一个进程组里,例如:
ps -xj | cat1 | cat2
如果想杀掉所有相关进程,就必须引入进程组的概念。以下是kill调用的方法:
int kill(pid_t pid, int signo);
pid==0 将信号发送给其进程组I D等于发送进程的进程组I D,而且发送进程有许可权向
其发送信号的所有进程。
pid<0 将信号发送给其进程组I D等于p i d绝对值,而且发送进程有许可权向其发送信号
的所有进程。
引入会话期与控制终端的意义:
会话期与控制终端的概念是因后台进程而生。
例如:tail -f log.file &
该进程不接收退出信号(ctrl + C),并且在用户退出登陆后依然存在,这种进程我们称为后台进程,后台进程的实现需要引入会话期与控制终端的概念。
1.对话期可以包括多个进程组。
2.一个对话期可以有一个单独的控制终端( controlling terminal)。这通常是我们在其上登录的终端设备(终端登录情况)或伪终端设备(网络登录情况)。
3.一个对话期中的几个进程组可被分成一个前台进程组( foreground process group)以及一个或几个后台进程组(background process group)
如果一个对话期有一个控制终端,则它有一个前台进程组,其他进程组则为后台进程组。
4.无论何时键入中断键(常常是D E L E T E或C t r l - C)或退出键(常常是C t r l - \),就会造成将中断信号或退出信号送至前台进程组的所有进程。
进程调用setsid函数就可建立一个新对话期。
如果调用此函数的进程不是一个进程组的组长,则此函数创建一个新对话期,结果为:
(1) 此进程变成该新对话期的对话期首进程(session leader,对话期首进程是创建该对话期的进程)。此进程是该新对话期中的唯一进程。
(2) 此进程成为一个新进程组的组长进程。新进程组id是此调用进程的进程ID。
(3) 此进程没有控制终端(下一节讨论控制终端)。如果在调用setsid之前此进程有一个控
制终端,那么这种联系也被解除。
如果此调用进程已经是一个进程组的组长,则此函数返回出错。为了保证不处于这种情况,
通常先调用fork,然后使其父进程终止,而子进程则继续。因为子进程继承了父进程的进程组ID,而其进程ID则是新分配的,两者不可能相等,所以这就保证了子进程不是一个进程组的组长。
精灵进程退出处理
当用户需要外部停止守护进程运行时,往往会使用 kill命令停止该守护进程。所以,守护进程中需要
编码来实现kill发出的signal信号处理,达到进程的正常退出