【转载】Linux 守护进程的编程方法

原文见:

http://www.linuxdevelop.org/tingxx/show.php?table=c&id=3

Linux 守护进程的编程方法

作者: 北京工业大学 小胡

守护进程(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(0);//是父进程,结束父进程

else if(pid< 0)

exit(1);//fork失败,退出

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

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

//并与控制终端分离

if(pid=fork())

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

else if(pid< 0)

exit(1);//fork失败,退出

//是第二子进程,继续

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

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

close(i);

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

umask(0);//重设文件创建掩模

return;

}

2. test.c清单

#include < stdio.h >

#include < time.h >

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

main()

{

FILE *fp;

time_t t;

init_daemon();//初始化为Daemon

while(1)//每隔一分钟向test.log报告运行状态

{

sleep(60);//睡眠一分钟

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

{

t=time(0);

fprintf(fp,"I'm here at %s\n",asctime(localtime(&t)) );

fclose(fp);

}

}

}

以上程序在RedHat Linux6.0下编译通过。步骤如下:

编译:gcc –g –o test init.c test.c

执行:./test

查看进程:ps –ef

从输出可以发现test守护进程的各种特性满足上面的要求。

linux+守护进程+php,【转载】Linux 守护进程的编程方法相关推荐

  1. linux 管道文件上机总结,[转载]LINUX 管道 fifo 等总结

    Linux进程通信:命名管道FIFO小结 Linux下进程之间通信可以用命名管道FIFO完成.命名管道是一种特殊类型的文件,因为Linux中所有事物都是文件,它在文件系统中以文件名的形式存在. 在程序 ...

  2. linux下jtag命令,[转载]LINUX内核调试过程(使用OpenJtag + OpenOCD)

    [转载]LINUX内核调试过程(使用OpenJtag + OpenOCD) (2012-04-12 02:02:27) 标签: 杂谈 [转载]LINUX内核调试过程(使用OpenJtag + Open ...

  3. linux下日志rorate,[转载]linux下日志分割logrotate 设置和理解

    对于Linux 的系统安全来说,日志文件是极其重要的工具.系统管理员能使用logrotate 程式用来管理系统中的最新的事件,对于Linux 的系统安全来说,日志文件是极其重要的工具.系统管理员能使用 ...

  4. linux打开core文件,[转载]linux下core文件设置与查看

    程序异常推出时,内核会生成一个core文件(是内存映像以及调试信息).可以通过使用gdb来查看core文件,指示出导致程序出错的代码所在的文件和行数. 1.查看系统中core文件生成的开关是否打开 1 ...

  5. linux ifort编译命令,[转载][Linux] icc与ifort编译器

    1.icc Intel C/C++编译器接受遵守ANSI C/C++ , ISO C/C++ standards,GNU inline ASM for IA-32 architecture标准的输入. ...

  6. linux 脚本竖线表示,[转载]Linux shell中的竖线(|)——管道符号

    vim一些常用的快捷键 快速注释: Ctrl+v I // esc 打开文件 gf ctrl+o MyBatis入门(五)---延时加载.缓存 一.创建数据库 1.1.建立数据库 /* SQLyog ...

  7. Linux非系统盘挂载,[转载] Linux mount 挂载分区、硬盘

    mount用于Linux系统挂载各种存储设备,如硬盘.分区.通常的用法 mount -t [文件系统] -o [选项参数] 设备分区 挂载点 例如 mount -t ext4 -o uid=501,g ...

  8. linux 下显卡优化,[转载]Linux 下 NVIDIA 显卡闭源驱动的一些优化

    完全搬运,原文请猛戳 NVIDIA 对开源驱动开发的支持之差从 Linus Torvalds 那句著名的"Fuck NVIDIA"就可见一斑--几乎没有提供任何开发文档,开源驱动的 ...

  9. linux fortran 内存不足,[转载]linux 安装fortran 90 --zz

    安装fortran 90 1 安装前需要的支持 1.1 环境Ubuntu10.04系统,(如果是其他系统可以跳过第2步) 1.2 安装库支持和alien等 sudo apt-get install b ...

  10. linux批量下载数据,[转载]linux shell批量下载IGS或CORS网FTP数据

    最近用迅雷FTP探测器下载数据,下载好之后发现漏下了好多数据,所以使用linux wget命令来实现FTP数据批量下载 关于wget命令可以 用wget --help 查看帮助,简单说明一下: wge ...

最新文章

  1. python导入excel数据-如何把python中的数据导入excel
  2. canal mysql重置_canal: 首先装完阿里的canal,然后数据库同步,仅供学习参考
  3. linux命令行总结
  4. python minimize_Python数学规划案例一
  5. 幼儿园视频监控系统设计方案
  6. Helpful C Tools:source、executables、debugging and performance tuning
  7. base64 string 放不下_String、byte[]、Base64相互转换,不要再用错了
  8. 最小环(【CCF】NOI Online能力测试 提高组第三题)
  9. 超分辨率技术如何发展?这6篇ECCV 18论文带你一次尽览
  10. 使用 IntraWeb (21) - 基本控件之 TIWTabControl
  11. 【考试总结贴】工程测量学
  12. Excel技能培训之十 选择性粘贴,单元格公式转换为数值,对每个单元格进行运算,行列转换,只粘贴非空值
  13. 例子, 防火墙配置domian比较策略
  14. 在Hyper-V中手动将.avhd合并到.vhd
  15. 2014-07-08 hibernate tenancy
  16. Gantt for .NET
  17. Jsp 案例:商品浏览记录
  18. android 如何刷机,安卓怎么刷机_安卓刷机图解_刷机大师教程
  19. mac悬浮窗_Mac OS 悬浮窗口,并且可以保持在全屏的其他应用上。
  20. 常见的二范数是什么意思?有什么用?

热门文章

  1. 开发函数计算的正确姿势——tensorflow serving
  2. Node.js 应用故障排查手册 —— 大纲与常规问题指标简介
  3. 黑科技揭秘:如何通过阿里云超算,使得汽车仿真效率提升25%
  4. 工程师如何解决穿衣搭配烦恼?——滴搭平台与算法 1
  5. 秘籍分享:如何将负载均衡按量付费实例转换为包年包月实例
  6. 数字孪生+交通,到底有啥用?
  7. 阿里的 RocketMQ 如何让双十一峰值之下0故障
  8. 云原生安全厂商小佑科技获达泰资本千万级投资
  9. 写速度提升20%,Elasticsearch 创始人给腾讯云发来感谢信
  10. Cloud一分钟 |格力电器营收比去年增长500亿元; 红黄蓝加盟停不下来;中美双方同意停止相互加征新的关税...