Chinaunix首页 | 论坛 | 博客
  • 博客访问: 824521
  • 博文数量: 92
  • 博客积分: 1498
  • 博客等级: 上尉
  • 技术积分: 993
  • 用 户 组: 普通用户
  • 注册时间: 2009-09-18 18:31
文章分类

全部博文(92)

文章存档

2013年(2)

2012年(3)

2011年(3)

2010年(61)

2009年(23)

分类: LINUX

2010-09-22 09:48:29

操作系统中常会听到守护进程,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,这说 明我们的守护进程在孤儿进程组中,他不是一个会话首进程,于是不会有机会分配到一个控制终端,所以,此守护进程被正确初始化了。
阅读(3065) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~