守护进程的概念

守护进程(Daemon)一般是为了保护我们的程序/服务的正常运行,当程序被关闭、异常退出等时再次启动程序/恢复服务。

例如 http 服务的守护进程叫 httpd,mysql 服务的守护进程叫 mysqld。

或者有时候我们需要让我们的程序/服务能不中断地运行,在关闭终端后也能在后台默默运行,除了可以这样:

nohup ./xxx &

,也可以写成 Daemon 程序,例如一个服务器。

许多服务器进程就是写成了 Daemon 程序,例如 Nginx、Redis、Apache 等。

Linux 中一般把守护进程放在/etc/init.d/中,启动服务时的命令一般是 /etc/init.d/* {start|stop|status|restart}

守护进程脱离终端而存在。当你执行命令ps -ef 时,守护进程的 PPID (父进程 ID)都是 1,TTY (终端)则是???

守护进程的创建

Linix 中可以调用 int daemon(int nochdir, int noclose); 函数来使程序成为一个守护进程。具体用法可以用“男人”命令(手册命令)查询:man daemon

通过原理我们也可以手动创建一个守护进程。

相关概念:

  • 进程组(Process Group): 进程集合,每个进程组有一个组长(Leader),其进程 ID 就是该进程组 ID。
  • 会话(Session): 进程组集合,每个会话有一个组长,其进程 ID 就是该会话组 ID。
  • 控制终端(Controlling Terminal):每个会话可以有一个单独的控制终端,与控制终端连接的 Leader 就是控制进程(Controlling Process)。

fork

守护进程的父进程是 init 进程,在创建时先从父进程 fork 出来一个子进程,退出父进程,这时子进程变成孤儿,就成了 init 的子进程。

子进程会继承父进程的会话,进程组,控制终端,文件描述符等。

setid

通过setid()来创建新会话,同时也脱离了原来的进程组,会话以及控制终端,成为新的会话的组长。此时它可能会再申请一个控制终端,所以我们再 fork 一下,并只保留新的子进程,这样就不是会话组长了,就不能申请控制终端了。

close(fd)

之后再关闭从父进程继承的文件描述符。至少要关闭 0,1,2 这三个文件描述符,分别对应了 stdin, stdout, 和 stderr。不过通常用 sysconf(_SC_OPEN_MAX) 获取系统允许的最大文件描述符个数,然后全部 close 掉。

关闭之后我们要将文件描述符 0,1,2 重新定向到 "/dev/null",防止新打开的文件的文件描述符为 0,1,2。

umask(0)

设置文件掩码是为了不受父进程的 umask 的影响,能自由创建读写文件和目录。

chdir("/")

守护进程一般是一直执行到系统关机,在它运行过程中,它所在的目录就不能卸载(unmounted)。通过将它的工作目录转移到根目录,用来的目录就允许卸载了。也不一定要根目录(这种情况,运行需要超级权限),可以选择一个不需要卸载的路径。

void daemon() {
// fork 出一个子进程。
pid_t pid = fork(); // fork 失败。
if( pid == -1) {
perror("fork");
exit(1);
} // 退出父进程。
if(pid) {
exit(0);
} // 创建新会话。
// 该子进程会成为新的会话和进程组的组长。
if(setsid() == -1) {
perror("setsid");
exit(1);
} // 再 fork 一次,新的子进程不再是会话组长。
pid = fork(); if( pid == -1) {
perror("fork");
exit(1);
} if(pid) {
exit(0);
} // 关掉从父进程继承的文件描述符。
int max_fd = sysconf(_SC_OPEN_MAX);
for(int i = 0; i < max_fd; ++i) {
close(i);
} // 重定向文件描述符 0, 1, 2 到 /dev/null
open("/dev/null", O_RDWR);
dup(0);
dup(0); // 设置文件创建权限掩码,不希望被父进程的掩码限制。
umask(0); // 将当前工作目录设置为系统根目录。
chdir("/");
}

守护进程(Daemon)的更多相关文章

  1. python 守护进程 daemon

    python 守护进程 daemon # -*-coding:utf-8-*- import sys, os '''将当前进程fork为一个守护进程 注意:如果你的守护进程是由inetd启动的,不要这 ...

  2. linux 守护进程 daemon

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

  3. linux下的守护进程daemon

    什么是守护进程?其实感觉守护进程并没有什么明确的定义,只是守护进程有一些特征,这是它需要遵循的. 守护进程的第一个特征是长时间在后台运行的程序,并且主要是为了提供某种服务,而为了能够让服务尽可能随时都 ...

  4. Linux守护进程daemon

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

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

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

  6. linux 守护进程(daemon process)代码-详细注释

    1. 进程组 组长不能创建新的 会话. 其它进程可以创建新的会话,创建后既成为会话首领,同时失去控制终端. 2. 会话首领可以重新打开控制终端 1 #include <stdio.h> 2 ...

  7. python学习笔记——线程threading (二)重写run()方法和守护进程daemon()

    1 run()方法 1.1 单个线程 在threading.Thread()类中有run()方法. from time import ctime,sleep import threading # 定义 ...

  8. Mac系统的launchd、守护进程daemon(2013笔记整理)

    1. launchd Mac系统下通用的进程管理器,是Mac系统下非常重要的一个进程,一般来说该进程不允许直接以命令行的形式调用.只能通过其控制管理界面,launchctl来进行控制. launchd ...

  9. flask使用debug模式时,存在错误时,会占用设备内存直至服务重启才释放;debug模式会开启一个守护进程(daemon process)

    函数调用顺序flask的app.py的run-->werkzeug的serving.py的run_simple-->调用werkzeug的debug的__init__.py里的类Debug ...

  10. 守护进程daemon.c

    它的特点是:•不占用控制终端(后台运行)•独立于控制终端•周期性运行 #include<stdio.h>#include<unistd.h>#include<fcntl. ...

随机推荐

  1. centos7 + python 2.7 + pip + openvswitch 杂项问题

    问题1: virtual box 安装centos7 后,网口无ip, 解决方法是:配置网口上电后,默认状态为down,  修改“onboot=yes”, 修改后保存配置重启系统. 2. 安装pip的 ...

  2. PHP技能树

  3. angular反向代理配置

    Angular-cli 是基于webpack 的一套针对提升angular开发体验的命令行工具. 开发vue的时候,基于webpack的时候当时配置一个反向代理以完全实现前后端分离的体验,既然webp ...

  4. 结对编程项目——C语言实现WordCount Web化

    结对编程项目 代码地址 201631062219,201631011410 gitee项目地址:https://gitee.com/xxlznb/pair_programming 作业地址:https ...

  5. 使用Linq的泛型功能

    泛型数据访问类: 业务抽象类使用数据访问类: 业务类继承业务抽象类: 使用业务类:

  6. 如何制作中文Javadoc包,并导入到Eclipse

    原理:使用chm转换工具将chm文件转换为zip文件,导入eclipse中即可. 准备 JDK1.9 API 中文 谷歌翻译版:http://www.pc6.com/softview/SoftView ...

  7. C#动态调用webService出现 基础连接已经关闭: 未能为 SSL/TLS 安全通道建立信任关系。

    这里因为的原因是https请求要检查证书,有些证书不正确的,网页不会正常展示内容,而会返回链接不安全,是否继续.不安全的链接是否继续. 详情参考: C#动态调用webService出现 基础连接已经关 ...

  8. Storm入门(三)HelloWorld示例

    一.配置开发环境 storm有两种操作模式: 本地模式和远程模式.使用本地模式的时候,你可以在你的本地机器上开发测试你的topology, 一切都在你的本地机器上模拟出来; 用远程模式的时候你提交的t ...

  9. 慢日志查询python flask sqlalchemy慢日志记录

    engine = create_engine(ProdConfig.SQLALCHEMY_DATABASE_URI, echo=True) app = Flask(__name__) app.conf ...

  10. loss函数和cost函数

    loss函数指单个样本的预测值和真值的偏差 cost函数指整体样本的预测值和真值的偏差