http://blog.csdn.net/zg_hover/article/details/2553321

http://blog.csdn.net/kongdefei5000/article/details/8808147

守护进程(Daemon)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程是一种很有用的进程。Linux的大多数服务器就是用守护进程实现的。比如,Internet服务器inetd,Web服务器httpd等。同时,守护进程完成许多系统任务。比如,作业规划进程crond,打印进程lpd等。
守护进程的编程本身并不复杂,复杂的是各种版本的Unix的实现机制不尽相同,造成不同Unix环境下守护进程的编程规则并不一致。这需要读者注意,照搬某些书上的规则(特别是BSD4.3和低版本的System V)到Linux会出现错误的。下面将全面介绍Linux下守护进程的编程要点并给出详细实例。
一. 守护进程及其特性
守护进程最重要的特性是后台运行。在这一点上DOS下的常驻内存程序TSR与之相似。其次,守护进程必须与其运行前的环境隔离开来。这些环境包括未关闭的文件描述符,控制终端,会话和进程组,工作目录以及文件创建掩模等。这些环境通常是守护进程从执行它的父进程(特别是shell)中继承下来的。最后,守护进程的启动方式有其特殊之处。它可以在Linux系统启动时从启动脚本/etc/rc.d中启动,可以由作业规划进程crond启动,还可以由用户终端(通常是shell)执行。
总之,除开这些特殊性以外,守护进程与普通进程基本上没有什么区别。因此,编写守护进程实际上是把一个普通进程按照上述的守护进程的特性改造成为守护进程。如果读者对进程有比较深入的认识就更容易理解和编程了。
二. 守护进程的编程要点
前面讲过,不同Unix环境下守护进程的编程规则并不一致。所幸的是守护进程的编程原则其实都一样,区别在于具体的实现细节不同。这个原则就是要满足守护进程的特性。同时,Linux是基于Syetem V的SVR4并遵循Posix标准,实现起来与BSD4相比更方便。编程要点如下;
1. 在后台运行。
为避免挂起控制终端将Daemon放入后台执行。方法是在进程中调用fork使父进程终止,让Daemon在子进程中后台执行。
if(pid=fork())
exit(0);//是父进程,结束父进程,子进程继续
2. 脱离控制终端,登录会话和进程组
有必要先介绍一下Linux中的进程与控制终端,登录会话和进程组之间的关系:进程属于一个进程组,进程组号(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清单

#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;
if(pid=fork())
exit();//是父进程,结束父进程
else if(pid< )
exit();//fork失败,退出
//是第一子进程,后台继续执行
setsid();//第一子进程成为新的会话组长和进程组长
//并与控制终端分离
if(pid=fork())
exit();//是第一子进程,结束第一子进程
else if(pid< )
exit();//fork失败,退出
//是第二子进程,继续
//第二子进程不再是会话组长 for(i=;i< NOFILE;++i)//关闭打开的文件描述符
close(i);
chdir("/tmp");//改变工作目录到/tmp
umask();//重设文件创建掩模
return;
}

2. test.c清单

#include < stdio.h >
#include < time.h > void init_daemon(void);//守护进程初始化函数 main()
{
FILE *fp;
time_t t;
init_daemon();//初始化为Daemon while()//每隔一分钟向test.log报告运行状态
{
sleep();//睡眠一分钟
if((fp=fopen("test.log","a")) >=)
{
t=time();
fprintf(fp,"Im here at %s/n",asctime(localtime(&t)) );
fclose(fp);
}
}
}

以上程序在RedHat Linux6.0下编译通过。步骤如下:
编译:gcc -g -o test init.c test.c
执行:./test
查看进程:ps -ef
从输出可以发现test守护进程的各种特性满足上面的要求。

说明:在系统调用库中有一个库函数可以直接使一个进程变成守护进程,
       #include <unistd.h>
       int daemon(int nochdir, int noclose);

如果nochdir的值为0,则将切换工作目录为根目录;如果noclose为0,则将标准输入,输出和标准错误都重定向到/dev /null

例子:

/*
*功能:创建一个守护进程,监视系统所有运行的进程
*/
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/resource.h> #include <unistd.h> int main()
{
FILE *fp;
FILE *fstream;
signal(SIGCHLD, SIG_IGN); // 忽略子进程结束信号,防止出现僵尸进程
daemon(,);//初始化守护进程,就是创建一个守护进程
while()
{
/*PID 进程ID ,user:进程开辟用户,comm:进程名,lstart:进程开始时间,etime:进程持续时间*/
fstream=popen("ps -eo pid,user,comm,lstart,etime>test.txt","r");
//如果执行命令失败,则写入错误报告
if(fstream==NULL)
{
//在打开或者创建error.log成功的情况下,写入错误(使用errno时失败)
if((fp = fopen("error.log", "a+")) != NULL)
{
fprintf(fp, "%s\n", "执行命令失败");
fclose(fp);
}
else
exit(); //写入错误失败,则终止程序推出并关闭所有进程
}
else
pclose(fstream); //关闭popen打开的I/O流
sleep(); //设置成5分钟获取一次系统进程情况
}
return ;
}

命令:gcc -o testdaemon testdaemon.c

编译程序

命令:./testdaemon

运行程序

命令:ps -ef| egrep 'testdaemon'

通过ps查看进程情况,可以看到进程的父进程id为1,即init进程

命令:lsof -c testdaemon

用lsof查看test进程所打开的文件,可以看到文件描述符0,1,2都被重定向到/dev/null

Linux守护进程的编程实现(转)的更多相关文章

  1. Linux守护进程的编程实现

    Linux 守护进程的编程方法 守护进程(Daemon)是执行在后台的一种特殊进程.它独立于控制终端而且周期性地执行某种任务或等待处理某些发生的事件.守护进程是一种非常实用的进程.Linux的大多数s ...

  2. 笔记整理--Linux守护进程

    Linux多进程开发(三)进程创建之守护进程的学习 - _Liang_Happy_Life__Dream - 51CTO技术博客 - Google Chrome (2013/10/11 16:48:2 ...

  3. linux 守护进程 daemon

    Linux的Service/Daemon你真的懂了吗? Linux 守护进程的启动方法 linux系统编程之进程(八):守护进程详解及创建,daemon()使用 linux守护进程 daemon 详解

  4. Linux守护进程简单介绍和实例具体解释

    Linux守护进程简单介绍和实例具体解释 简单介绍 守护进程(Daemon)是执行在后台的一种特殊进程.它独立于控制终端而且周期性地执行某种任务或等待处理某些发生的事件.守护进程是一种非常实用的进程. ...

  5. Linux守护进程编写指南

    Linux守护进程编写指南 守护进程(Daemon)是运行在后台的一种特殊进程.它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件.守护进程是一种很有用的进 程.Linux的大多数服务器 ...

  6. .NET跨平台实践:用C#开发Linux守护进程

    Linux守护进程(Daemon)是Linux的后台服务进程,它脱离了与控制终端的关联,直接由Linux init进程管理其生命周期,即使你关闭了控制台,daemon也能在后台正常工作. 一句话,为L ...

  7. .NET跨平台实践:用C#开发Linux守护进程(转)

    Linux守护进程(Daemon)是Linux的后台服务进程,它脱离了与控制终端的关联,直接由Linux init进程管理其生命周期,即使你关闭了控制台,daemon也能在后台正常工作. 一句话,为L ...

  8. [转]❲阮一峰❳Linux 守护进程的启动方法

    ❲阮一峰❳Linux 守护进程的启动方法 "守护进程"(daemon)就是一直在后台运行的进程(daemon). 本文介绍如何将一个 Web 应用,启动为守护进程. 一.问题的由来 ...

  9. Server Develop (七) Linux 守护进程

    守护进程 守护进程,也就是通常说的Daemon进程,是Linux中的后台服务进程.它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件.守护进程常常在系统引导装 ...

随机推荐

  1. 程序员的复仇:11行代码如何让Node.js社区鸡飞狗跳

    来源自:http://www.techug.com/node-js-community 几天前,一名 NPM(Node.js Package Manager)社区的贡献者 Azer Koçulu 出于 ...

  2. Codeforces Round #236 (Div. 2) C. Searching for Graph(水构造)

    题目大意 我们说一个无向图是 p-interesting 当且仅当这个无向图满足如下条件: 1. 该图恰有 2 * n + p 条边 2. 该图没有自环和重边 3. 该图的任意一个包含 k 个节点的子 ...

  3. Maven更新父子模块的版本号

    前置条件: 1.安装有吃饭的家伙JAVA和MAVEN. 首先,需要有一个packaging类型为pom的pom.xml文件即我们的parent项目pom文件.在这个parent项目中配置好groupI ...

  4. 基于 CentOS7 的 Kubernetes 集群

    一.环境 相关主机 master 192.168.12.197 minion 192.168.12.198~232 etcd 192.168.12.233~236 相关软件 OS CentOS 7 软 ...

  5. 【转载】给VM虚拟机增加硬盘容量

    转载自:http://www.douban.com/note/53678368/ vmware-vdiskmanager [选项]这里的选项你必须包含以下的一些选择项或参数选项和参数描述<dis ...

  6. nodeJS 菜鸟入门

    从一个简单的 HTTP 服务开始旅程-- 创建一个 server.js 文件,写入: //最简单的 http 服务例子 var http = require("http"); ht ...

  7. Android 学习笔记 Service

    PS:前几篇的内容光是上代码了,也没有细细的讲解..感觉这样写很不好..因此还是多一些讲解吧... 学习内容: 1.了解Service... 2.Service的启动与停止.. 3.绑定与取消绑定Se ...

  8. 轻量级.NET ORM、高性能.NET ORM 之 SqlSugar 开源ORM - ASP.NET

    3.0最新API: http://www.cnblogs.com/sunkaixuan/p/5911334.html 1.前言/Preface SqlSugar从去年到现在已经一年了,版本从1.0升到 ...

  9. Linux文件打包压缩、解压缩、备份命令使用方法(转载)

    对于刚刚接触Linux的人来说,一定会给Linux下一大堆各式各样的文件名给搞晕.别个不说,单单就压缩文件为例,我们知道在Windows下最常见的压缩文件就只有两种,一是,zip,另一个是.rar.可 ...

  10. DBSet Class(EF基础系列11)

    Method Name Return Type          Description Add Added entity type Adds the given entity to the cont ...