您的位置:首页 > 运维架构 > Linux

linux中的守护进程daemon

2010-05-12 21:45 357 查看
一. 守护进程及其特性

(1)最重要的特征是后台运行

(2)必须与运行前的环境隔离开来。这些环境通常是守护进程从执行它的父进程中继承下来的。环境包  括还未关闭的文件描述符,控制终端,会话和进程组,工作目录以及文件创建淹模等。

(3)启动方式。可以由用户终端执行,也可以从启动脚本/etc/rc.d中启动。

总之,编写守护进程实际上是把一个普通进程按照上述的守护进程的特性改造成为守护进程。

 

二.守护进程的编程要点

1.在后台运行

 为避免挂起控制终端将daemon放入后台执行。方法是在进程中调用fork使父进程终止,让daemon 再子进程中后台执行。

2.脱离终端控制,登入会话和进程组

  在1的基础上,调用setsid()使第一个子进程成为会话组长。由于会话过程对终端的独占性,进程同时与控制终端脱离。

     setsid();

3.禁止进程重新打开控制终端

  现在,进程已经成为无终端的会话组长。但它可以重新申请打开一个控制终端。

    可以通过使进程不再成为会话组长来禁止进程重新打开控制终端:

 

if(pid=fork())

     exit(0); //结束第一子进程,第二子进程继续(第二子进程不再是会话组长)

4. 关闭打开的文件描述符

  进程从创建它的父进程那里继承了打开的文件描述符。如不关闭,将会浪费系统资源,

    造成进程所在的文件系统无法卸下以及引起无法预料的错误。按如下方法关闭它们:

 

for(i=0;i 关闭打开的文件描述符close(i);>

5. 改变当前工作目录

  进程活动时,其工作目录所在的文件系统不能卸下(即每个进程都由一个工作目录)。一般需要将工作目录改变到根目录。

    对于需要转储核心,写运行日志的进程将工作目录改变到特定目录如 /tmpchdir("/")

6. 重设文件创建掩模

  进程从创建它的父进程那里继承了文件创建掩模。它可能修改守护进程所创建的文件的存取位。

    为防止这一点,将文件创建掩模清除:umask(0);

 

7. 处理SIGCHLD信号

  处理SIGCHLD信号并不是必须的。

    但对于某些进程,特别是服务器进程往往在请求到来时生成子进程处理请求。

    如果父进程不等待子进程结束,子进程将成为僵尸进程(zombie)从而占用系统资源。

    如果父进程等待子进程结束,将增加父进程的负担,影响服务器进程的并发性能。

    在Linux下可以简单地将 SIGCHLD信号的操作设为SIG_IGN。

 

signal(SIGCHLD,SIG_IGN);

  这样,内核在子进程结束时不会产生僵尸进程。

 

三.守护进程实例

包括两部分:主程序daemon.c 和 初始化守护进程程序init_daemon.c

 

1.daemon.c

 

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <time.h>

 

void init_daemon(void);//守护进程初始化函数

 

int main(void) {

time_t t;

FILE* fp;

 

init_daemon();//初始化守护进程

 

while(1)

{

sleep(5);

if((fp = fopen("test1.log","a")) >= 0)

{

t = time(0);

fprintf(fp,"I am here at %s/n",asctime(localtime(&t)));

fclose(fp);

}

}

}

 

 

2. init_daemon.c

 

#include <unistd.h>

#include <signal.h>

#include <sys/param.h>

#include <sys/types.h>

#include <sys/stat.h>

 

void init_daemon(void)

{

int pid;

int i;

//parent的fork返回子进程的pid(当然>0),子进程的fork返回0。

if(pid = fork())//如果是父进程,结束父进程

exit(0);

else if(pid < 0)//fork()失败,退出

exit(1);

 

//是第一子进程,后台继续执行

setsid();//第一个子进程成为新的会话组组长和进程组长。

//并与控制终端分离

 

if(pid = fork())

exit(0);//是第一子进程,结束第一子进程。

else if(pid < 0)

exit(1);

 

//是第一子进程,继续

//第二子进程不再是会话组长

for(i = 0; i < NOFILE;++i)//关闭打开的文件描述符

{

close(i);

}

 

chdir("/tmp"); //改变工作目录到/tmp

umask(0);//重设文件,创建淹没

 

return;

}

 

 

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息