ngx_int_t
ngx_daemon(ngx_log_t *log)
{int  fd;// 让init进程成为新产生进程的父进程:// 调用fork函数创建子进程后,使父进程立即退出。这样,产生的子进程将变成孤儿进程,并被init进程接管,// 同时,所产生的新进程将变为在后台运行。switch (fork()) {case -1:ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "fork() failed");return NGX_ERROR;case 0:break;default:exit(0);}ngx_pid = ngx_getpid();// 调用setsid()函数脱离控制终端和进程组,使该进程成为会话组长,并与原来的登录会话和进程组脱离。// 此时进程已经成为无终端的会话组长,但它可以重新申请打开一个控制终端。// 为了避免这种情况,可以通过使进程不再成为会话组长来禁止进程重新打开控制终端,// 这就需要第二次调用fork()函数(nginx没有做这一步)。父进程(会话组长)退出,子进程继续执行,// 并不再拥有打开控制终端的能力。在正在执行的进程中调用INIT_DAEMON后,进程将成为守护进程,// 脱离控制终端进入后台执行。if (setsid() == -1) {ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "setsid() failed");return NGX_ERROR;}// 重设文档创建掩模// 很多情况下,守护进程会创建一些临时文件。出于安全性的考虑,往往不希望这些文件被别的用户查看。// 这时,可以使用umask函数修改文件权限,创建掩码的取值,以满足守护进程的要求。umask(0);// 关闭打开的文档描述符:// 新产生的进程从父进程继承了某些打开的文件描述符,如果不使用这些文件描述符,则需要关闭它们。// 守护进程是运行在系统后台的,不应该在终端有任何的输出信息。// 可以使用dup函数将标准输入、输出和错误输出重定向到/dev/null设备上//(/dev/null是一个空设备,向其写入数据不会有任何输出)。fd = open("/dev/null", O_RDWR);if (fd == -1) {ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,"open(\"/dev/null\") failed");return NGX_ERROR;}if (dup2(fd, STDIN_FILENO) == -1) {ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDIN) failed");return NGX_ERROR;}if (dup2(fd, STDOUT_FILENO) == -1) {ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDOUT) failed");return NGX_ERROR;}#if 0if (dup2(fd, STDERR_FILENO) == -1) {ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDERR) failed");return NGX_ERROR;}
#endifif (fd > STDERR_FILENO) {if (close(fd) == -1) {ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "close() failed");return NGX_ERROR;}}// 改变当前工作目录(nginx没有做)// 使用fork函数产生的子进程将继承父进程的当前工作目录。// 当进程没有结束时,其工作目录是不能被卸载的。// 为了防止这种问题发生,守护进程一般会将其工作目录更改到根目录下(/目录)。return NGX_OK;
}

setsid相关知识:

通过调用setsid函数,使得新创建的进程脱离控制终端,同时创建新的进程组,并成为该进程组的首进程。为了使读者更好地理解这一步骤,下面介绍进程组、会话(session)的基本概念。

在Linux系统中,所有的进程都属于各自的进程组。进程组是一个或多个进程的集合。打个比方,可以认为某个班级是一个进程组,而其中成员就是进程。一个班级至少有一个成员。当一个班级的最后一个成员不存在的时候,这个班级也就不存在了,也就是进程组消亡了。

每个进程组都有类似于进程号的标识,称为进程组ID。进程组ID是由领头进程的进程号决定的,每个进程组都存在一个领头进程。进程组的存在与否与领头进程是否存在没有关系。

会话是一个或多个进程组的集合。与进程组类似,每个会话都存在一个领头进程。Linux是一个多用户的操作系统,在同一时刻系统中会存在属于不同用户的多个进程。如果用户在某个终端上发送了某个信号,例如,按下“Ctrl+C”发送SIGINT信号,如何确保信号被正确地发送到对应的进程,同时不会影响使用其他终端的用户的进程?

会话和进程组是Linux内核用于管理多用户情况下用户进程的方法。每个进程都属于一个进程组,而进程组又属于某个会话。当用户从终端登录系统(不管是终端还是伪终端),系统会创建一个新的会话。在该终端上启动的进程都会被系统划归到会话的进程组中。

会话中的进程通过该会话中的领头进程(常称其为控制进程)与一个终端相连。该终端是会话的控制终端。一个会话只能有一个控制终端,反之一样。如果会话存在一个控制终端,则它必然拥有一个前台进程组。属于该组的进程可以从控制终端获得输入。这时,其他的进程组都为后台进程组。图8.3所示为会话、进程组、进程与控制终端之间的关系。

由于守护进程没有控制终端,而使用fork函数创建的子进程继承了父进程的控制终端、会话和进程组,因此,必须创建新的会话,以脱离父进程的影响。Linux系统提供了setsid函数用于创建新的会话。

setsid函数将创建新的会话,并使得调用setsid函数的进程成为新会话的领头进程。调用setsid函数的进程是新创建会话中的惟一的进程组,进程组ID为调用进程的进程号。setsid函数产生这一结果还有个条件,即调用进程不为一个进程的领头进程。由于在第一步中调用fork的父进程退出,使得子进程不可能是进程组的领头进程。该会话的领头进程没有控制终端与其相连。至此,满足了守护进程没有控制终端的要求。

参考:http://www.cnblogs.com/xuxm2007/archive/2011/07/29/2121280.html

linux下daemon守护进程的实现(以nginx代码为例)相关推荐

  1. linux中Daemon守护进程编程

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

  2. another mysql daemon,[守护进程详解及创建,daemon()使用

    一,守护进程概述 Linux Daemon(守护进程)是运行在后台的一种特殊进程.它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件.它不需要用户输入就能运行而且提供某种服务,不是对整个 ...

  3. Linux下ps查找进程用kill终止命令

    Linux下ps查找进程用kill终止命令<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:offic ...

  4. linux怎么监控守护进程,linux shell脚本守护进程监控svn服务

    最近搭建的svn服务不知道什么原因服务总是被关闭(如果你不知道怎么搭建svn可以参考linux下搭建svn版本控制软件),因此用shell脚本实现一个守护进程.用于监控svn服务是否启动,如果服务不在 ...

  5. arch下aria2c守护进程等配置小结

    arch下aria2c守护进程等配置小结 前言 aria2c是个好东西,可以把他简单理解为是下载管理器的后端,配合一些前端程序,比如ariaNG,可以管理其下载的各类东西,再配合百度云导出真实下载地址 ...

  6. C语言实现Linux系统的守护进程创建

      大家好,我是练习编程时长两年半的昆工第一ikun,今天我们来分享一下进程的有关知识,并且用c语言来创建一个Linux系统的守护进程. 目录 一.进程相关接口函数 1.创建子进程 -- fork ( ...

  7. 在linux下python爬虫进程发生异常时自动重启直至正常结束的方法

    在linux下python爬虫进程发生异常时自动重启直至正常结束的方法 参考文章: (1)在linux下python爬虫进程发生异常时自动重启直至正常结束的方法 (2)https://www.cnbl ...

  8. linux下两个进程可以同时打开同一个文件吗?返回的文件描述符一样吗?

    Linux下两个进程可以同时打开同一个文件吗?返回的文件描述符一样吗? 一:结论 1.两个进程中分别产生生成两个独立的fd 2.两个进程可以任意对文件进行读写操作,操作系统并不保证写的原子性 3.进程 ...

  9. kill掉多个进程linux中的sudo,linux下批量kill进程的方法

    --kill某个用户下的所有进程(用户为test) --pkill # pkill -u test --killall # killall -u test --ps # ps -ef | grep t ...

最新文章

  1. activity 启动模式_腾讯大牛:你根本不懂Activity!
  2. DS, ES, SS, DI, SI, BP, SP, IP, FS 寄存器
  3. 互联网思维-标签思维(1)
  4. video.min.js php,使用flv.js与video.js做一个视频直播效果
  5. 自己做的几个小软件(数学工具和游戏),用C/C#制作,用到许多相关的C#技术细节,可以免费提供下载,感兴趣的,来看一下...
  6. 任务分配算法c语言,基于蚁群算法多Agent任务分配方法.pdf
  7. 命令行import torch正常,但pycharm中显示“No module named torch”解决方法
  8. 检查硬件变化的命令kudzu
  9. QT 多线程程序设计 -互斥
  10. Ubuntu18 安装yum
  11. Java SE书籍推荐
  12. Android Media Framework(3): Stagefright框架流程解读
  13. iOS一代码搞定定位
  14. 未来的计算机 展望未来作文,展望未来作文素材_2020展望未来作文精选5篇
  15. 两台计算机远程桌面连接不上去,远程桌面连接不上怎么办
  16. 国际金融统计 (IFS) 数据库1978-2020
  17. 书籍_《未来世界的幸存者》阮一峰--2/5
  18. 《自控力》读后感——意志力与认识自己
  19. 抖音小店无货源,怎么操作可以出单?资深电商人在线分享
  20. saiku 2.6 源码整合(无maven情况下)

热门文章

  1. BootStrap入门教程 (二)
  2. 一文彻底搞懂字符串、字符串常量池原理
  3. Spark源码打包编译的过程
  4. Java高并发编程详解系列-线程安全数据同步
  5. redis的HyperLogLog与布隆过滤器
  6. DDD(领域驱动设计)系列之一-DomainPrimitive
  7. 计算机网络引言,[计算机网络]Ch.1引言
  8. 问题:pom文件有删除线,不能识别maven模块
  9. 什么是Redis的VM机制
  10. spring boot入门学习---热部署