Linux daemon进程的应用、实现和原理

Linux Deamon函数 Daemon库函数。 作用: 守护进程是生存期长的一种进程,因为他没有控制终端,他们是在后台运行的。调用daemon()函数将该进程设置为一个守护进程。 比如: 执行命令: ping 4.2.2 & 会释放终端,但是还是会在屏幕上面输出,需要使用,deamon,完全交由后台运行。 函数原型: int daemon(int nochdir ,int ... 阅读详情

什么情况下用daemon进程

生产环境下,除了我们ssh登录上去,然后手动跑的那部分以外,其他都是自动运行的,这些大部分都应该是后台执行的。如何才能后台执行呢?

  1. nohup ./XXX & 
  2. 由系统的其他daemon进程启动。这样的话,你的程序是它的子进程,跟终端没关系。退出终端也不会导致进程退出。如写在crontab里。 
  3. 写成daemon程序,可以手动执行,退出终端时程序不退出。

如何选择呢?

(1)首先,清理过期日志这一类需求,可以写一个死循环一直运行,也可以写在crontab里,每次执行完就退出(如果每分钟一次可以满足的话);

(2)crontab的需要接受最多1分钟的时延,如果实时性要求更高一些,那么就需要考虑写个死循环了,这个程序可以由crontab来start和restart,只有在挂了重启时才会出现1分钟时延;

* * * * * /usr/bin/flock -nx /home/chenming/lock/test1.lock -c '/home/chenming/test1 >/dev/null 2>&1'
(3)服务不能中断的(nginx、redis、apache,所有在线服务),一般都是daemon程序。但理论上用(2)似乎也可以;当然这两者细节上有很多区别。

怎么用daemon进程

linux C/C++可以直接调用int daemon(int, int)函数,不需要自己重新实现。示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
 
int main(int argc, char *argv[]) {
    if (argc < 3) {
        printf("Usage: $0 no_ch_dir no_close_fd\n");
        exit(0);
    }

    int no_ch_dir = atoi(argv[1]);
    int no_close_fd = atoi(argv[2]);

    std::cout << "main pid : " << getpid() << std::endl;
    std::cout << "main parent pid : " << getppid() << std::endl;
    std::cout << "main pwd : " << get_current_dir_name() << std::endl;
    if (daemon(no_ch_dir, no_close_fd) != 0) {
        // 一般都用daemon(0,0)
        // 成功返回0,失败返回-1
        // daemon(0,0):chdir到/,关闭0,1,2描述符。
        std::cout << "stdout: daemon = -1" << std::endl;
        std::cerr << "stderr: daemon = -1" << std::endl;
        return 1;
    }
    std::cout << "stdout: daemon = 0" << std::endl;
    std::cerr << "stderr: daemon = 0" << std::endl;
 
    std::cout << "sub pid : " << getpid() << std::endl;
    std::cout << "sub parent pid : " << getppid() << std::endl;
    std::cout << "sub pwd : " << get_current_dir_name() << std::endl;
    while (1);
    return 0;
}

编译运行:

[chenming@localhost ~]$ g++ test1.cc -o test1
[chenming@localhost ~]$ ./test1 0 0
main pid : 7978
main parent pid : 1382
main pwd : /home/chenming
[chenming@localhost ~]$ ps -ef | grep test1
94:chenming  7864  7573  0 16:09 pts/0    00:00:16 vim test1.cc
95:chenming  7897     1 97 16:14 ?        00:33:07 ./test1 0 0
97:chenming  7979     1 47 16:48 ?        00:00:04 ./test1 0 0
99:chenming  7981  1382  8 16:49 pts/1    00:00:00 grep -inE --color test1
[chenming@localhost ~]$ ll /proc/7979/fd
total 0
lrwx------. 1 chenming chenming 64 May  1 16:49 0 -> /dev/null
lrwx------. 1 chenming chenming 64 May  1 16:49 1 -> /dev/null
lrwx------. 1 chenming chenming 64 May  1 16:49 2 -> /dev/null
[chenming@localhost ~]$ lsof -p 7979
COMMAND  PID     USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
test1   7979 chenming  cwd    DIR  253,0     4096      2 /
test1   7979 chenming  rtd    DIR  253,0     4096      2 /
test1   7979 chenming  txt    REG  253,0     8355 142259 /home/chenming/test1
test1   7979 chenming  mem    REG  253,0   122232  52742 /lib/libgcc_s-4.4.7-20120601.so.1
test1   7979 chenming  mem    REG  253,0   142600  38788 /lib/ld-2.12.so
test1   7979 chenming  mem    REG  253,0  1906308  38865 /lib/libc-2.12.so
test1   7979 chenming  mem    REG  253,0   202040  47921 /lib/libm-2.12.so
test1   7979 chenming  mem    REG  253,0   942040  52866 /usr/lib/libstdc++.so.6.0.13
test1   7979 chenming    0u   CHR    1,3      0t0   3903 /dev/null
test1   7979 chenming    1u   CHR    1,3      0t0   3903 /dev/null
test1   7979 chenming    2u   CHR    1,3      0t0   3903 /dev/null

man 3 daemon可以查看到函数签名:

#include <unistd.h>

int daemon(int nochdir, int noclose);

怎么写daemon进程

1.fork,父进程退出

2.setsid。跟终端脱离关系。

3.umask、关掉0,1,2文件描述符。

4.chdir

5.信号处理

这里只有1和 2是必须的。3一般都会做;5大部分不做。

自己实现一个:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>

int daem(int no_ch_dir, int no_close_fd) {
    int pid = fork();
    if (pid < 0) {
        return -1;
    }else if (pid > 0){
        exit(0);
    }

    if (setsid() < 0) {
        return -1;
    }

    if (no_ch_dir == 0) {
        chdir("/");
    }

    umask(0);

    if (no_close_fd == 0) {
        close(0);
        close(1);
        close(2);
    }
    return 0;
}

redis的实现:

void daemonize(void) {
    int fd;

    if (fork() != 0) exit(0); /* parent exits */
    setsid(); /* create a new session */

    /* Every output goes to /dev/null. If Redis is daemonized but
     * the 'logfile' is set to 'stdout' in the configuration file
     * it will not log at all. */
    if ((fd = open("/dev/null", O_RDWR, 0)) != -1) {
        dup2(fd, STDIN_FILENO);
        dup2(fd, STDOUT_FILENO);
        dup2(fd, STDERR_FILENO);
        if (fd > STDERR_FILENO) close(fd);
    }
}


memcached的实现:

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "memcached.h"

int daemonize(int nochdir, int noclose)
{
    int fd;

    switch (fork()) {
    case -1:
        return (-1);
    case 0:
        break;
    default:
        _exit(EXIT_SUCCESS);
    }

    if (setsid() == -1)
        return (-1);

    if (nochdir == 0) {
        if(chdir("/") != 0) {
            perror("chdir");
            return (-1);
        }
    }

    if (noclose == 0 && (fd = open("/dev/null", O_RDWR, 0)) != -1) {
        if(dup2(fd, STDIN_FILENO) < 0) {
            perror("dup2 stdin");
            return (-1);
        }
        if(dup2(fd, STDOUT_FILENO) < 0) {
            perror("dup2 stdout");
            return (-1);
        }
        if(dup2(fd, STDERR_FILENO) < 0) {
            perror("dup2 stderr");
            return (-1);
        }

        if (fd > STDERR_FILENO) {
            if(close(fd) < 0) {
                perror("close");
                return (-1);
            }
        }
    }
    return (0);
}

nginx的实现:

#include <ngx_config.h>
#include <ngx_core.h>


ngx_int_t
ngx_daemon(ngx_log_t *log)
{
    int  fd;

    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();

    if (setsid() == -1) {
        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "setsid() failed");
        return NGX_ERROR;
    }

    umask(0);

    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 0
    if (dup2(fd, STDERR_FILENO) == -1) {
        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDERR) failed");
        return NGX_ERROR;
    }
#endif

    if (fd > STDERR_FILENO) {
        if (close(fd) == -1) {
            ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "close() failed");
            return NGX_ERROR;
        }
    }

    return NGX_OK;
}




daemon deamon生命周期很长。在后台运行并且不拥有控制终端。deamon用来指向特殊任务,如:cron:一个在规定时间执行命令的daemon。sshd:安全shell deamon,允许在远程主机上使用一个安全的通信协议登录系统。httpd:HTTP服务器daemon,用于Web页面。inetd:Internet超级服务器daemon,监听从指定的TCP/IP端口上进入的网络连接并启动相应的服务器程序来处理这些连接。通常将daemon程序的名称以字母d结尾。 阅读详情

相关推荐

linux下的守护进程和系统日志

文章目录 #守护进程daemon ##系统日志 ###代码示例

makunIT的博客 4418

Linux系统守护进程(daemon)的内部实现

1. 概述 github项目地址:https://github.com/superwujc 尊重原创,欢迎转载,注明出处:https://my.oschina.net/superwjc/blog/1811314 守护进程通常具有2个特征: 1. 随系统启动而运行,直到系统关闭,因而长...

ciguaxi2841的博客 258

Linux C daemon源码

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <syslog.h> #include <errno.h> #include <signal.h> #define FNAME "/tmp

phongqi的博客 345

linux 守护进程:PM2、systemd、Forever、Daemontools、supervisor

守护进程(Daemon Process),也就是通常说的 Daemon 进程(精灵进程),是 Linux 中的后台服务进程。它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程是个特殊的孤儿进程,这种进程脱离终端,为什么要脱离终端呢?之所以脱离于终端是为了避免进程被任何终端所产生的信息所打断,其在执行过程中的信息也不在任何终端上显示。

freeking101的博客 7607

编写daemon进程,检测信号实现功能

编写一个后台进程。当检测到SIGHUP(远程挂断)信号时,该进程获得系统运行时间(读取/proc/uptime文件,该文件第一列为系统启动到现在的时间(以秒为单位),第二列为系统空闲的时间(以秒为单位)),将其追加写入日志文件。 检测到SIGUSR1信号,后台进程退出。

LDA模型参数优化实战:从auto设置到passes调优

本文深入探讨了LDA主题模型的参数优化实战,重点解析了如何通过设置alpha='auto'与eta='auto'让模型自适应语料,并详细阐述了passes参数对训练效果的核心影响。文章提供了系统的调优方法与评估策略,旨在帮助用户从“能用”到“用好”LDA,产出清晰、可解释的主题分析结果。

weixin_29163797的博客 118

daemon(守护进程)

Daemon   Daemon程序是一直运行的服务端程序,又称为守护进程。通常在系统后台运行,没有控制终端不与前台交互,Daemon程序一般作为系统服务使用。Daemon是长时间运行的进程,通常在系统启动后就运行,在系统关闭时才结束。一般说Daemon程序在后台运行,是因为它没有控制终端,无法和前台的用户交互。Daemon程序一般都作为服务程序使用,等待客户端程序与它通信。我们也把运行的Daem

沧海一粟的专栏 3万+

Excel插件开发实战:从零封装一个带自定义Ribbon的.xlam工具包

本文详细介绍了如何从零开发一个带自定义Ribbon的Excel插件.xlam工具包。通过VBA和XML技术,读者将学习到插件架构设计、Ribbon界面定制、模块化开发以及企业级部署策略,帮助提升Excel自动化办公效率。

weixin_42531128的博客 517

【linux系统编程学习笔记】第二节:进程的应用场景分析(pid_t vfork、Daemon进程/精灵进程、系统日志/openlog)

认真和耐心总会帮你解决大部分难题。 进程的应用场景分析进程的应用场景调用第三方程序相关APIpid_t vfork(void);//进程复刻Daemon进程(翻译:精灵进程、后台进程、守护进程)系统日志相关APIvoid openlog(const char *ident, int option, int facility);//打开系统日志 进程的应用场景 调用第三方程序 守护进程/精灵进程(服务) 调用第三方程序相关API exec系列函数: #include <unistd.h>.

qq_44796935的博客 586

Cursor设置界面汉化保姆级教程:手把手教你修改JS文件实现中文界面(附避坑指南)

本文提供Cursor编辑器设置界面汉化的详细教程,从定位JS文件到安全修改实现中文界面,包含必备工具清单、文件路径指引和常见问题解决方案。通过手把手教学帮助用户轻松完成汉化,提升使用体验,特别适合不熟悉英文界面的开发者。

weixin_29007809的博客 1414

INMP441麦克风与ESP32的I2S音频采集实战指南

本文提供了INMP441数字麦克风与ESP32开发板通过I2S接口进行高质量音频采集的完整实战指南。详细讲解了硬件连接、软件配置、数据读取及基础处理,并分享了常见的避坑技巧与性能优化建议,帮助开发者快速构建物联网音频应用。

weixin_28396629的博客 598

Linux《进程间关系和守护进程》

本文介绍了进程组、会话和守护进程等概念,并展示了如何将网络计算器服务器程序改造为守护进程。主要内容包括:1. 进程组概念及组长进程的作用;2. 会话的组成和会话首进程;3. 控制终端与进程关系;4. 作业控制相关操作;5. 守护进程的实现原理,通过setsid函数创建独立会话;6. 详细实现了Dameon函数,包含工作目录切换和标准流处理;7. 将网络计算器服务器改造为守护进程后,即使关闭Xshell终端也能继续运行。最后指出可以通过系统提供的daemon函数简化守护进程创建过程。

mljy.博客 1548

VTK实战笔记(1)在win11搭建VTK-9.4.2 + qt5.15.2 + VS2019_x64开发环境

Visual Studio 2019 + qt5.15.2 + vtk9.4.2

心向阳光,斗志昂扬! 977

daemon函数实现原理

linux提供了daemon函数用于创建守护进程,实现原理如下: #include int daemon(int nochdir, int noclose); 1. daemon()函数主要用于希望脱离控制台,以守护进程形式在后台运行的程序。 2. 当nochdir为0时,daemon将更改进城的根目录为root(“/”)。 3. 当noclose为0是,daemo

liubeck的专栏 606

C#上位机实战:借助NetToPLCSim与西门子S7-1200仿真通信全攻略

本文详细介绍了如何使用C#开发上位机程序,通过NetToPLCSim与西门子S7-1200进行仿真通信的全过程。从环境准备、PLC仿真环境搭建、网络配置到C#代码实现,提供了完整的实战指南和常见问题解决方案,帮助开发者快速掌握工业自动化通信技术。

weixin_30596343的博客 440

【存储原理】IO超时处理 块层block-scsi层之间

【存储原理】IO超时处理 块层block-scsi层之间

sinat_37817094的博客 1024

永不消逝的进程

后台守护进程是 Linux/Unix 系统中非常重要的"地下工作者"。本文从 Linux/Unix 的进程组和会话的机制入手,详细的介绍了基于这些机制之上的两种截然不同的实现守护进程的手法。在深入解读这些奇淫巧技的同时,笔者也更希望读完本文的朋友们能够触类旁通,对 Linux/Unix 系统的进程间关系能有更深一层的认识。

liwg06 555

YOLOv11改进策略【模型轻量化】| 替换轻量化骨干网络:ShuffleNet V1

本文记录的是基于ShuffleNet V1的YOLOv11轻量化改进方法研究。ShuffleNet利用和操作降低计算成本,克服了现有先进架构在极小网络中因 1×1 卷积计算成本高而效率低的问题。相比一些传统的网络架构,能更好地。本文配置了原论文中和四种模型,以满足不同的需求。

Limiiiing的博客 1229

-守护进程-

当关闭一个会话时,其中的前台进程会随会话终止而退出,但后台进程不会直接退出,它们会被系统进程(PPID 显示为 1)“领养”,此时会话虽被保留,但 TPGID 会显示为 -1(当前进程与终端的关联状态异常或未明确初始化),这表明后台进程仍会受到用户登录和退出的影响。若要让后台进程完全不受用户登录与注销的影响,需要将其进行守护进程化处理,具体可通过让其自成一个新会话来实现,使其脱离原终端和会话的控制,成为独立运行的系统级进程,这样之前的会话不管如何登录、注销,都不会对这个新会话中的进程产生影响。

2403_82706967的博客 894

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

Avahi架构详解:从daemon到客户端工具,一文看懂零配置网络的实现原理

Avahi是一款开源的零配置网络实现方案,它通过mDNS(多播DNS)和DNS-SD(DNS服务发现)协议,让设备在局域网内无需手动配置IP地址和DNS服务器即可自动发现和通信。本文将深入解析Avahi的架构设计,从核心守护进程到客户端工具,帮助读者全面理解零配置网络的实现原理。 ## 一、Avahi核心组件解析 🧩 Avahi的架构采用模块化设计,主要由守护进程、客户端库和工具集三部分组成

gitblog_00815的博客 519

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

C语言中的Daemon进程:系统守护者的秘密

本文介绍了C语言中Daemon进程的概念与实现。Daemon进程是一种在后台运行的特殊进程,没有控制终端,通常用于提供系统级服务。文章通过对比表格展示了Daemon进程与普通进程的关键区别,详细讲解了创建Daemon进程的8个核心步骤,并提供了完整的代码示例。此外,还通过系统架构图说明了Daemon进程在系统中的位置,以及两个典型应用场景(系统日志服务和网络服务)的具体实现代码。这些内容为开发者理解和使用Daemon进程提供了实用指导。

道阻其长,未来可期。笔耕不辍,行则将至! 1846

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

Linux系统守护进程(Daemon)

守护进程是 Linux 系统的核心组成部分,负责在后台默默提供服务。理解其原理和管理方式,对系统运维和开发至关重要。现代 Linux 系统通常通过。是一种在后台长期运行的特殊进程,通常不直接与用户交互,而是为系统或其他应用程序提供服务。管理守护进程,简化了传统。在 Linux 系统中,

漫谈网络 1849

jsvc进程占满Linux服务器cpu,jsvc 启动Java 在Linux下的实现原理

jsvc 启动Java 在Linux下的实现原理jsvc 是在apache的daemon项目下开源项目,主要功能可以使一些运行在普通用户下的java进程获取一些root权限下的权利,比如端口在1024下等。如何运行在自己的java代码中,实现start, init , stop,destroy的方法,将自己的编译打成jar文件, 通过调用jsvc 来启动./jsvc -java-home /u...

weixin_42512021的博客 908

linux守护进程的作用和原理、创建守护进程的三种方式

守护进程(Daemon)是在操作系统中运行的一种特殊类型的后台进程。它在系统启动时启动,并在系统关闭时终止,与用户交互的终端会话无关。守护进程通常在后台运行,不会与用户进行直接的交互,也不会被用户终止。守护进程通常用于执行一些系统级的任务和服务,比如网络服务、数据库服务、日志记录、定时任务等。它们在系统运行时一直保持活动状态,为其他应用程序或用户提供服务。

叶新东老师的博客 1136

[Linux_OS] core dump | session | 守护进程daemon

setsid的用法还是有点复杂了,在setsid 生成新会话后还要close,open, 为此Linux提供了另一个系统调用daemon

No Game No Life 1232

daemon进程

转自:http://blog.chinaunix.net/uid-27105712-id-3356916.html         为什么一定要使用daemon进程呢?Linux中每一个系统与用户进行交流的界面称为终端(terminal),每一个从此终端开始运行的进程都会依附于这个终端,这个终端就称为这些进程的控制终端(Controlling terminal),当控制终端被关闭时,相应的进

Nothing replaces hard work! 784
上一篇: Linux daemon进程原理与使用
下一篇: chkconfig与service的用法与原理
纯属虚构
博客等级 码龄17年 86粉丝 194原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值