操作系统中常会听到守护进程,init就是我们常常听说的一个系统守护进程,linux内核当中的守护进程也不胜枚举:kevened(提供进程上
下文),kapmd (对很多计算机系统提供高级电源管理提供支持)等等。
使用ps 命令可以看到,大部分的守护进程都以超级用户特权运行,没有一个守护进程具有控制终端,其终端名设置为:?
终端前台进程组ID为-1,内核守护进程以无控制终端方式启动。用户层守护进程缺少控制终端可能是因为守护进程调用了setsid的结果,所有用户层守护
进程都是进程组组长的进程以及会话的首进程,而且是进程组和会话中的唯一进程。还有应该注意的大多数守护进程的父进程是init进程。
初始化一个守护进程有以下6点需要注意:
1.首先需调用umask将文件模式创建屏蔽字设置为0
2.调用fork( ),然后使父进程退出。
3.调用setsid创建一个新的会话。
4.将当前工作目录更改为根目录
5.关闭不再需要的文件描述符
6.将文件描述符0,1,2定向到/dev/null 使其不具有和终端交互的效果
下面看一个简单的初始化的例子
/*
* Copyright (c) 2010-~ zhouyongfei
*
* The source code is released for free distribution under the terms of the GNU General Public License
*
*
* Author: alen Chou
* Created Time: 2010年09月21日 星期二 20时27分20秒
* File Name: testdaemon.c
* Description:
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
#include <fcntl.h>
#include <time.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <signal.h>
void daemonize(const char *cmd)
{
int i,fd0,fd1,fd2;
pid_t pid;
struct rlimit rl;
struct sigaction sa;
//首先调用umask将文件模式创建屏蔽字设置为0
umask(0);
//得到每个进程能打开的最大数文件数
if(getrlimit(RLIMIT_NOFILE , &rl) < 0){
printf("%s:cannot get file limit",cmd);
exit(0);
}
//创建一个子进程,然后父进程退出,这样保证了子进程不是一个进程组的组长进程
if((pid = fork()) <0 ){
printf("%s: cannot fork",cmd);
exit(0);
}else if(pid != 0){
exit(0);
}
//利用这个子进程创建一个会话1,成为新会话的首进程,2,成为一个新进程组的组长,3,没有控制终端
setsid();
sa.sa_handler = SIG_IGN;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if(sigaction(SIGHUP,&sa,NULL) < 0){
printf("%s,cannot ignore SIGHUP",cmd);
exit(0);
}
if((pid = fork()) < 0){
printf("%s:cannot fork()",cmd);
exit(0);
}else if(pid != 0){
exit(0);
}
//改变当前的工作目录为根“/”目录
if(chdir("/") < 0){
printf("%s:cannot change directory tp /",cmd);
exit(0);
}
//关闭当前进程打开的所有文件描述符
if(rl.rlim_max == RLIM_INFINITY)
rl.rlim_max = 1024;
for(i = 0;i < rl.rlim_max; i++)
close(i);
//将标准输入输出和标准操作输出都定向到/dev/null,让其不实现和标准输入输出等设备的交互
fd0 = open("/dev/null" ,O_RDWR);
fd1 = dup(0);
fd2 = dup(0);
//初始化一个系统日志,用于记录不能和终端交互的daemon进程的相关信息
openlog(cmd,LOG_CONS,LOG_DAEMON);
if(fd0 != 0 || fd1 != 1 || fd2 != 2){
syslog(LOG_ERR,"unexpected file description %d %d %d",fd0,fd1,fd2);
exit(1);
}
}
int main(int argc, char *argv[])
{
daemonize("ls");
sleep(10);//这里必须使用 sleep使其处于休眠状态,使用下面的死循环将不能看到实际的效果
/*while(1){
;
}*/
return 0;
} |
编译:$ gcc testdaemon.c -o testdaemon
运行:$ ./testdaemon
查看:
zhou@zhou:~/linuxc/process$ ps aux | grep ./testdaemon
zhou 2622 0.0 0.0 1612 196 ? S 09:07 0:00
./testdaemon
zhou 2624 0.0 0.0 3544 828 pts/0 S+ 09:07 0:00 grep
–color=auto ./testdaemon
看上面查看的结果,2622进程的状态是S,终端名称号为?,这些都符合守护进程的特征,然后再使用ps命令查看,没有活动的进程的ID是2622,这说
明我们的守护进程在孤儿进程组中,他不是一个会话首进程,于是不会有机会分配到一个控制终端,所以,此守护进程被正确初始化了。
阅读(1555) | 评论(0) | 转发(0) |