守护进程(Daemon)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待
    处理某些发生的事件。守护进程是一种很有用的进程。 
    Linux的大多数服务器就是用守护进程实现的。比如,Internet服务器inetd,Web服务器httpd等。
    同时,守护进程完成许多系统任务。比如,作业规划进程crond,打印进程lpd等。

  守护进程的编程本身并不复杂,复杂的是各种版本的Unix的实现机制不尽相同,
    造成不同 Unix环境下守护进程的编程规则并不一致。
    需要注意,照搬某些书上的规则(特别是BSD4.3和低版本的System V)到Linux会出现错误的。
    下面结合一些前辈的文档和自己的例子说说守护进程的编程。

.基本概念
.进程
    .每个进程都有一个父进程
    .当子进程终止时,父进程会得到通知并能取得子进程的退出状态。
.进程组
    .每个进程也属于一个进程组
    .每个进程主都有一个进程组号,该号等于该进程组组长的PID号
    .一个进程只能为它自己或子进程设置进程组ID号
.会话期
    .对话期(session)是一个或多个进程组的集合。
    .setsid()函数可以建立一个对话期:
    如果,调用setsid的进程不是一个进程组的组长,此函数创建一个新的会话期。
    (1)此进程变成该对话期的首进程
    (2)此进程变成一个新进程组的组长进程。
    (3)此进程没有控制终端,如果在调用setsid前,该进程有控制终端,那么与该终端的联系被解除。
    如果该进程是一个进程组的组长,此函数返回错误。
    (4)为了保证这一点,我们先调用fork()然后exit(),此时只有子进程在运行,
    子进程继承了父进程的进程组ID,但是进程PID却是新分配的,所以不可能是新会话的进程组的PID。
    从而保证了这一点。

if((pid=fork())>0)  //parent
        exit(0);
    else if(pid==0){        //th1 child
        setsid();           //th1是成为会话期组长
        if(fork() ==0){     //th2不会是会话期组长(变成孤儿进程组)
            ...
        }
    }

一. 守护进程及其特性

(1)守护进程最重要的特性是后台运行。在这一点上DOS下的常驻内存程序TSR与之相似。
    (2)其次,守护进程必须与其运行前的环境隔离开来。这些环境包括未关闭的文件描述符,控制终端,
    会话和进程组,工作目录以及文件创建掩模等。这些环境通常是守护进程从执行它的父进程(特别是shell)
    中继承下来的。
    (3)最后,守护进程的启动方式有其特殊之处。它可以在Linux系统启动时从启动脚本/etc/rc.d中启动,
    可以由作业规划进程crond启动,还可以由用户终端(通常是 shell)执行。
  总之,除开这些特殊性以外,守护进程与普通进程基本上没有什么区别。
    因此,编写守护进程实际上是把一个普通进程按照上述的守护进程的特性改造成为守护进程。

二. 守护进程的编程要点  (来自UEAP)

  前面讲过,不同Unix环境下守护进程的编程规则并不一致。所幸的是守护进程的编程原则其实都一样,
      区别在于具体的实现细节不同。这个原则就是要满足守护进程的特性。
      同时,Linux是基于Syetem V的SVR4并遵循Posix标准,实现起来与BSD4相比更方便。编程要点如下;

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

if(pid=fork())
    exit(0); //是父进程,结束父进程,子进程继续

2. 脱离控制终端,登录会话和进程组
  进程属于一个进程组,进程组号(GID)就是进程组长的进程号(PID)。登录会话可以包含多个进程组。
    这些进程组共享一个控制终端。这个控制终端通常是创建进程的登录终端。
    控制终端,登录会话和进程组通常是从父进程继承下来的。
    我们的目的就是要摆脱它们,使之不受它们的影响。
    方法是在第1点的基础上,调用setsid()使进程成为会话组长:

setsid();

  说明:当进程是会话组长时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);

  这样,内核在子进程结束时不会产生僵尸进程。
    这一点与BSD4不同,BSD4下必须显式等待子进程结束才能释放僵尸进程。

三. 守护进程实例
  守护进程实例包括两部分:主程序test.c和初始化程序init.c。
    主程序每隔一分钟向/tmp目录中的日志test.log报告运行状态。
    初始化程序中的init_daemon函数负责生成守护进程。读者可以利用init_daemon函数生成自己的守护进程。

1. init.c清单

 1 #include < unistd.h >
2 #include < signal.h >
3 #include < sys/param.h >
4 #include < sys/types.h >
5 #include < sys/stat.h >
6
7 void init_daemon(void)
8 {
9 int pid;
10 int i;
11 if(pid=fork())
12 exit(0); //是父进程,结束父进程
13 else if(pid< 0)
14 exit(1); //fork失败,退出
15 //是第一子进程,后台继续执行
16 setsid(); //第一子进程成为新的会话组长和进程组长
17 //并与控制终端分离
18 if(pid=fork())
19 exit(0); //是第一子进程,结束第一子进程
20 else if(pid< 0)
21 exit(1); //fork失败,退出
22 //是第二子进程,继续
23 //第二子进程不再是会话组长
24 for(i=0;i< NOFILE;++i) //关闭打开的文件描述符
25 close(i);
26
27 chdir("/tmp"); //改变工作目录到/tmp
28 umask(0); //重设文件创建掩模
29 return;
30 }
31
32 2. test.c清单
33
34 #include < stdio.h >
35 #include < time.h >
36
37 void init_daemon(void);//守护进程初始化函数
38
39 main()
40 {
41 FILE *fp;
42 time_t t;
43 init_daemon();//初始化为Daemon
44
45 while(1)//每隔一分钟向test.log报告运行状态
46 {
47 sleep(60);//睡眠一分钟
48 if((fp=fopen("test.log","a")) >=0){
49 t=time(0);
50 fprintf(fp,"Im here at %sn",asctime(localtime(&t)) );
51 fclose(fp);
52 }
53 }
54 }

以上程序在RedHat Linux6.1下编译通过。步骤如下:
编译:gcc -g -o test init.c test.c
执行:./test
查看进程:ps -ef

说明:在系统调用库中有一个库函数可以直接使一个进程变成守护进程,

1 #include <unistd.h>
2 int daemon(int nochdir, int noclose);

Daemon Process的更多相关文章

  1. Android Studio: Failed to sync Gradle project 'xxx' Error:Unable to start the daemon process: could not reserve enough space for object heap.

    创建项目的时候报错: Failed to sync Gradle project 'xxx' Error:Unable to start the daemon process: could not r ...

  2. Android Studio新建了一个项目提示Error:Unable to start the daemon process

    提示如下错误:

  3. Run python as a daemon process

    I am using `&`: why isn't the process running in the background?     No problem. We won't show y ...

  4. A daemon process class in python

    In everbright task schedule project, we need some daemon process to do certain work, here is a examp ...

  5. 越狱开发-创建真正的后台程序(Daemon Process)

    在网上搜索了一下如何在IOS上面实现Daemon Process,只有chrisalvares的博客中有过详细的描述,但是其博客中描述的较为复杂, 参考stackoverflow中的一个问答: htt ...

  6. 【error】Gradle sync failed: Unable to start the daemon process.【已解决】

    ---恢复内容开始--- 在克隆GIT项目后,Android Studio 报错: Gradle sync failed: Unable to start the daemon process. Th ...

  7. Android studio Unable to start the daemon process

    Unable to start the daemon process.This problem might be caused by incorrect configuration of the da ...

  8. ionic android - Unable to start the daemon process. Could not reserve enough space for 2097152KB object heap

    Unzipping C:\Users\app\.gradle\wrapper\dists\gradle-4.1-all\bzyivzo6n839fup2jbap0tjew\gradle-4.1-all ...

  9. android studio Error:Unable to start the daemon process【转】

    本文转载自:https://blog.csdn.net/dhx20022889/article/details/44919905 我在用android studio 做一个小项目,在家里的mac电脑中 ...

随机推荐

  1. 点击EditText可编辑,点击其他地方不可编辑

    我是在Fragment中实现的,在网上查了,有的说要回调Activity的onTouch事件,通过实验直接在Fragment中即可.如下: 我的EditText在ScrollView,因为Scroll ...

  2. webstrom Certificate validation failed

    今天好烦.因为装了一个webstrome,我的svn不管用了. 为了防止webstrom,我的日期改了,日期改了,csdn登不上去了.告诉我时期不对. 草草哦哦. 这就是那个svn出问题之后的画面. ...

  3. javascript数组&省市联动分别用js数组和JSON实现

    1.定义数组的三种方式: **数组可以存放不同的数据类型   第一种: var arr=[1,2,3];   var arr=[1,"2",true];   第二种: 使用内置对象 ...

  4. .net 下word 中的图片与文字分离

    最近在做一个项目要求word 中的图片与文字分离 ,找了好久终于找到一个完美的方法 c#实现word中的图文分离   part 1: class define Code highlighting pr ...

  5. 《Cracking the Coding Interview》——第12章:测试——题目4

    2014-04-25 00:35 题目:没有专门的测试工具,你要如何对一个网页进行压力测试? 解法:拼手速,拼电脑数量呗.快捷键+复制粘贴网址,狂搞一番.话说回来,有脚本语言的情况下,直接写个脚本来模 ...

  6. [转]如何像Python高手(Pythonista)一样编程

    本文转自:http://xianglong.me/article/how-to-code-like-a-pythonista-idiomatic-python 最近在网上看到一篇介绍Pythonic编 ...

  7. PC Server远程管理卡用户管理脚本实现

    1.IPMI工作原理图: 2.脚本实现流程图: 3.适配服务器机型: 4.演示效果: 5.实现代码: #!/usr/bin/env bash # Author : JACK ZHAO # Date : ...

  8. SELECTORS模块实现并发简单版FTP

    环境:windows, python 3.5功能:使用SELECTORS模块实现并发简单版FTP允许多用户并发上传下载文件 结构:ftp_client ---| bin ---| start_clie ...

  9. django的F和Q对象

    F表达式和Q表达式: # 示例模型如下 class Book(models.Model): """图书模型""" name = models ...

  10. maven学习(十八)——用Nexus搭建Maven私服

    一.搭建nexus私服的目的 为什么要搭建nexus私服,原因很简单,有些公司都不提供外网给项目组人员,因此就不能使用maven访问远程的仓库地址,所以很有必要在局域网里找一台有外网权限的机器,搭建n ...