热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【转载】对守护进程的一点理解

守护进程的相关知识LinuxC编程实战上只简略地用了2页书的内容就过了,但是根据我的实际情况和一些了解,我认为无论是从它的重要性,还是我自己的理解程度来说,书上的2页可是远远不够啊

守护进程的相关知识Linux C编程实战上只简略地用了2页书的内容就过了,但是根据我的实际情况和一些了解,我认为无论是从它的重要性,还是我自己的理解程度来说,书上的2页可是远 远不够啊!于是乎,在搜罗了一些资料以后,我觉得还是写篇博客总结归纳一下比较好,也比较有助于以后的学习!


在介绍守护进程之前,我们首先了解一下以下几个概念
0.终端(terminal):每一个 用户 与 系统 进行交流的界面.(也就是在linux中按 ctrl+alt+t 弹出的字符界面那个框框)
1.进程组:是一个或多个进程的集合.(以进程为最小组成单位的集合)
2.组长进程:进程组中 进程号 等于 进程组ID 的进程. 组长进程的退出不影响进程组ID !!
3.会话期:是一个或多个进程组的集合.(以进程组为最小单位的集合,注意与进程组的概念相结合理解)


零.什么是守护进程
守护进程,也叫Daemon进程,它是Linux系统中的一种后台服务进程,通常 独立于控制终端并且周期性的执行某种任务或者等待处理某些发生的事件.
类似于Windows中的系统服务,也就是在桌面和任务栏看不到,但是打开任务管理器中又显示正在运行的程序.(在linux中可以在终端输入ps -ef查看)


一.为何创建守护进程
在Linux中,有一些需要自 开机启动系统至关机关闭系统一直运行 或 收到特定指令才关闭,以此来完成某些任务的程序,这些程序就是守护进程.
说白了,创建守护进程就是为了系统能正常的完成某些任务,但是又不占用多余的资源.


二.如何创建守护进程
0.创建子进程,退出父进程
首先,守护进程是脱离终端的(因为它要在后台运行,操作系统有那么多守护进程,不可能从开机到关机一直有一个或多个终端处于开启状态吧!).所以创建的时候 必须是当前进程的子进程(如果是父进程的话,退出终端程序就结束了),而且必须保证 只有子进程运行.
所以具体代码如下:

点击(此处)折叠或打开

  1. pid = fork();
  2. if (pid > 0) //退出父进程,使得子进程成为后台进程
  3.     exit(0);
  4. else if (pid < 0) //创建失败,返回-1
  5.     return -1;



此时,该子进程就成为一个孤儿进程,由1号进程(init)收养,它就成为init进程的子进程.


1.在子进程中创建新会话
虽然第一步已经使子进程脱离的父进程,但是创建子进程时调用了fork函数,子进程全盘拷贝了父进程的会话期,进程组,控制终端等,虽然父进程退出了,但 是会话期,进程组等并未改变,因此子进程并没有真正的独立!所以现在要使用setsid来使进程完全独立,摆脱其他进程的控制.
setsid函数用于创建一个新会话,并担任该会话组的组长,具体作用有一下几个方面:
0).让进程摆脱原会话的控制;
1).让进程摆脱原进程组的控制;
2).让进程摆脱原控制终端的控制.
(关于以上功能如何实现,笔者未做深入了解)
实现代码:
setsid();   //建立新的进程组,使该子进程成为进程组的首进程,从而脱离所有终端
注意:当进程是会话组长时,调用setsid会失败,但是第0步已经保证该进程不会是会话组长&#xff08;因为该进程的父进程已是会话组长&#xff09;,调用setsid后,该进程会成为新的会话组长和进程组长,并与原来的会话组的进程组脱离.


2.禁止进程重新打开控制终端
经过以上步骤,该进程已经成为一个无终端的会话组长,但是该进程仅仅只是脱离了父进程运行的那个控制终端,它自己还可以打开另外的终端,为避免这种情况,可以使该进程不再是会话组长来实现,再次使用fork创建子进程,并使调用fork的进程退出.
实现代码同第1步


3.改变当前目录为根目录
同样的,使用fork创建子进程的时候,子进程拷贝了父进程的工作目录,但是守护进程工作时,应该在一个相对较稳定的目录下运行,不然若是该目录被卸载,守护进程就不能正常工作了!(比如在使用Windows的时候,强行把C盘里的系统文件删除一些,下次再进入系统的时候还能正常进入吗?而且貌似系统文件是删不掉的!)
实现代码:
chdir("/"); //改变工作目录,使进程不与任何文件系统联系 (当然也可以改变为其他一些比较稳定的目录,不一定非是根目录)


4.重设文件屏蔽字
由于使用fork,子进程拷贝了父进程的文件屏蔽字,这给子进程的使用带来的诸多麻烦.所以,把该子进程的文件屏蔽字设为0可以大大增强该守护进程的灵活性.
实现代码:
umask(0); //将文件屏蔽字设置为0


5.关闭文件描述符 (这一步可以通俗的称为:父进程摆下的烂摊子,子进程来收拾!呵呵)
同屏蔽字一样,子进程从父进程那里继承了一些已经打开的文件,这些文件可能永远不会被子进程读写,但它们一样消耗系统资源,而且可能导致所在的文件系统无法卸载.
由于第2步已经使守护进程脱离了终端,所以该守护进程的一些需要终端来完成的功能就完成不了了,比如用printf()输出一行字符,已经不能实现了!所以文件描述符为0,1和2的三个文件(输入,输出和报错)已经失去价值了,应该被关闭!
实现代码:
for (i &#61; 0; i

6.守护进程的退出处理
前面的步骤已经基本实现了守护进程的功能,但只是我们 需要守护进程的时候 那样做,如果我们需要把守护进程结束应该怎么办呢?
此时,我们就需要使用kill命令停止守护进程.
实现代码:

点击(此处)折叠或打开

  1. signal(SIGTERM, sigterm_handler);


  2. void sigterm_handler(int arg)
  3. {
  4.        _running &#61; 0;
  5. }





三.完整代码实现daemon进程
综合前面的所有步骤,我们就可以得到一个简单的守护进程:(功能为每隔10秒在系统日志中写入当前的系统时间)

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <sys/param.h>
  3. #include <sys/types.h>
  4. #include <unistd.h>
  5. #include <signal.h>
  6. #include <time.h>
  7. #include <syslog.h>
  8. #include <sys/stat.h>

  9. volatile sig_atomic_t _running &#61; 1;

  10. void sigterm_handler(int arg)
  11. {
  12.     _running &#61; 0;
  13. }

  14. int init_daemon(void)
  15. {
  16.     pid_t pid;
  17.     int i;

  18.     pid &#61; fork();
  19.     if (pid > 0)
  20.         exit(0);
  21.     else if (pid < 0)
  22.         return -1;         //第一步

  23.     setsid();             //第二步

  24.     pid &#61; fork();
  25.     if (pid > 0)
  26.         exit(0);
  27.     else if (pid < 0)
  28.         return -1;         //第三步

  29.     chdir("/");             //第四步

  30.     umask(0);             //第五步

  31.     for (i &#61; 0; i < NOFILE; close(i&#43;&#43;));//第六步

  32.     return 0;
  33. }

  34. int main()
  35. {
  36.     time_t now;
  37.     init_daemon();

  38.     syslog(LOG_USER | LOG_INFO, "测试守护进程!\n");
  39.         
  40.     signal(SIGTERM, sigterm_handler); //第七步

  41.     while(_running)
  42.         {
  43.         sleep(10);
  44.         time(&now);
  45.         syslog(LOG_USER | LOG_INFO, "系统时间: \t%s\t\t\n", ctime(&now));
  46.     }

  47.     return 0;
  48. }

 

转:https://www.cnblogs.com/pengdonglin137/articles/3239042.html



推荐阅读
  • 数字图书馆近期展出了一批精选的Linux经典著作,这些书籍虽然部分较为陈旧,但依然具有重要的参考价值。如需转载相关内容,请务必注明来源:小文论坛(http://www.xiaowenbbs.com)。 ... [详细]
  • Android 构建基础流程详解
    Android 构建基础流程详解 ... [详细]
  • 本文探讨了如何通过编程手段在Linux系统中禁用硬件预取功能。基于Intel® Core™微架构的应用性能优化需求,文章详细介绍了相关配置方法和代码实现,旨在帮助开发人员有效控制硬件预取行为,提升应用程序的运行效率。 ... [详细]
  • 为了确保iOS应用能够安全地访问网站数据,本文介绍了如何在Nginx服务器上轻松配置CertBot以实现SSL证书的自动化管理。通过这一过程,可以确保应用始终使用HTTPS协议,从而提升数据传输的安全性和可靠性。文章详细阐述了配置步骤和常见问题的解决方法,帮助读者快速上手并成功部署SSL证书。 ... [详细]
  • MATLAB字典学习工具箱SPAMS:稀疏与字典学习的详细介绍、配置及应用实例
    SPAMS(Sparse Modeling Software)是一个强大的开源优化工具箱,专为解决多种稀疏估计问题而设计。该工具箱基于MATLAB,提供了丰富的算法和函数,适用于字典学习、信号处理和机器学习等领域。本文将详细介绍SPAMS的配置方法、核心功能及其在实际应用中的典型案例,帮助用户更好地理解和使用这一工具箱。 ... [详细]
  • 深入解析CAS机制:全面替代传统锁的底层原理与应用
    本文深入探讨了CAS(Compare-and-Swap)机制,分析了其作为传统锁的替代方案在并发控制中的优势与原理。CAS通过原子操作确保数据的一致性,避免了传统锁带来的性能瓶颈和死锁问题。文章详细解析了CAS的工作机制,并结合实际应用场景,展示了其在高并发环境下的高效性和可靠性。 ... [详细]
  • PHP预处理常量详解:如何定义与使用常量 ... [详细]
  • 基于Linux系统的Kickstart自动化服务器部署方案
    本文针对企业需求,提出了一种基于Linux系统的Kickstart自动化服务器部署方案。该方案旨在通过无盘批量安装操作系统,提高企业IT基础设施的部署效率。Kickstart是一种利用Anaconda工具实现服务器自动化安装的技术,能够显著简化和加速操作系统的安装过程。通过详细的实施规划,本文介绍了Kickstart的工作原理及其在实际部署中的应用,为企业提供了高效的自动化部署解决方案。 ... [详细]
  • 在《Linux高性能服务器编程》一书中,第3.2节深入探讨了TCP报头的结构与功能。TCP报头是每个TCP数据段中不可或缺的部分,它不仅包含了源端口和目的端口的信息,还负责管理TCP连接的状态和控制。本节内容详尽地解析了TCP报头的各项字段及其作用,为读者提供了深入理解TCP协议的基础。 ... [详细]
  • 在对WordPress Duplicator插件0.4.4版本的安全评估中,发现其存在跨站脚本(XSS)攻击漏洞。此漏洞可能被利用进行恶意操作,建议用户及时更新至最新版本以确保系统安全。测试方法仅限于安全研究和教学目的,使用时需自行承担风险。漏洞编号:HTB23162。 ... [详细]
  • 提升视觉效果:Unity3D中的HDR与Bloom技术(高动态范围成像与光线散射)
    提升视觉效果:Unity3D中的HDR与Bloom技术(高动态范围成像与光线散射) ... [详细]
  • 在ElasticStack日志监控系统中,Logstash编码插件自5.0版本起进行了重大改进。插件被独立拆分为gem包,每个插件可以单独进行更新和维护,无需依赖Logstash的整体升级。这不仅提高了系统的灵活性和可维护性,还简化了插件的管理和部署过程。本文将详细介绍这些编码插件的功能、配置方法,并通过实际生产环境中的应用案例,展示其在日志处理和监控中的高效性和可靠性。 ... [详细]
  • 深入剖析Java中SimpleDateFormat在多线程环境下的潜在风险与解决方案
    深入剖析Java中SimpleDateFormat在多线程环境下的潜在风险与解决方案 ... [详细]
  • 在处理 XML 数据时,如果需要解析 `` 标签的内容,可以采用 Pull 解析方法。Pull 解析是一种高效的 XML 解析方式,适用于流式数据处理。具体实现中,可以通过 Java 的 `XmlPullParser` 或其他类似的库来逐步读取和解析 XML 文档中的 `` 元素。这样不仅能够提高解析效率,还能减少内存占用。本文将详细介绍如何使用 Pull 解析方法来提取 `` 标签的内容,并提供一个示例代码,帮助开发者快速解决问题。 ... [详细]
  • 在多堆石子游戏中,通过分析Nim博弈策略,探讨了如何在限定时间和内存条件下实现最优解。本文详细研究了石子游戏中的数学原理和算法优化方法,旨在为参与者提供有效的策略指导。具体而言,文章讨论了不同堆数下的Nim值计算及其应用,帮助玩家在复杂的博弈环境中取得优势。 ... [详细]
author-avatar
翔未央图_971
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有