Linux Daemon Writing HOWTO
这里视频讲的很清楚
牛客网-c/C++Linux课程-守护进程

int main() {// 1.创建子进程,退出父进程pid_t pid = fork();if(pid > 0) {exit(0);}// 2.将子进程重新创建一个会话setsid();// 3.设置掩码umask(022);// 4.更改工作目录chdir("/home/nowcoder/");// 5. 关闭、重定向文件描述符int fd = open("/dev/null", O_RDWR);dup2(fd, STDIN_FILENO);dup2(fd, STDOUT_FILENO);dup2(fd, STDERR_FILENO);// 6.业务逻辑// 捕捉定时信号struct sigaction act;act.sa_flags = 0;act.sa_handler = work;sigemptyset(&act.sa_mask);sigaction(SIGALRM, &act, NULL);struct itimerval val;val.it_value.tv_sec = 2;val.it_value.tv_usec = 0;val.it_interval.tv_sec = 2;val.it_interval.tv_usec = 0;// 创建定时器setitimer(ITIMER_REAL, &val, NULL);// 不让进程结束while(1) {sleep(10);}return 0;
}

1
什么是守护进程?
守护进程是后台运行,自动运行,少交互或不交互。
守护进程(或服务)是一个后台进程,设计为自动运行,几乎不需要用户干预。ApacheWeb服务器http守护程序(httpd)就是这样一个守护程序示例。它在后台监听特定端口,并根据请求类型提供页面或处理脚本。

在Linux中创建守护进程会按照给定的顺序使用一组特定的规则。了解它们是如何工作的将有助于您了解守护进程在userland Linux中是如何运行的,但也可以通过对内核的调用来运行。事实上,一些守护进程与与与硬件设备(如外部控制器板、打印机和PDA)一起工作的内核模块接口。它们是Linux的基本构建块之一,为Linux提供了难以置信的灵活性和强大功能。

在本教程中,将用C语言构建一个非常简单的守护进程。随着我们的深入,将添加更多代码,显示启动和运行守护进程所需的正确执行顺序。
2.开始

首先,您需要在Linux机器上安装以下软件包来开发守护进程,具体来说:

GCC 3.2.2或更高版本

Linux开发头和库

如果您的系统尚未安装这些组件(不太可能,但还是要检查),则需要它们来开发本指南中的示例。要了解您安装的GCC版本,请使用:

gcc——版本

3.规划你的守护进程

3.1它将做什么?

守护进程应该做一件事,并且做得很好。这一点可能与管理多个域上的数百个邮箱一样复杂,也可能与编写报告并调用sendmail将其发送给管理员一样简单。

在任何情况下,你都应该有一个很好的计划来指导守护进程应该做什么。如果它将与你可能或可能不写的其他守护进程进行交互操作,那么这也是另一个需要考虑的问题。

3.2有多少互动?

守护进程永远不应该通过终端与用户直接通信。事实上,守护进程根本不应该与用户直接通信。所有通信都应该通过某种类型的接口(您可能需要也可能不需要编写),这种接口可以像GTK+GUI一样复杂,也可以像信号集一样简单。

4.基本守护程序结构

当守护进程启动时,它必须做一些低级的家务来为自己真正的工作做好准备。这包括几个步骤:

 Fork off the parent processChange file mode mask (umask)Open any logs for writingCreate a unique Session ID (SID)Change the current working directory to a safe placeClose standard file descriptorsEnter actual daemon code
放弃父进程更改文件模式掩码(umask)打开所有日志进行写入创建唯一的会话ID(SID)将当前工作目录更改为安全位置关闭标准文件描述符输入实际的守护程序代码

4.1分叉父进程

守护进程由系统本身或终端或脚本中的用户启动。当它启动时,这个过程就像系统上的任何其他可执行文件一样。为了使其真正自治,必须在执行实际代码的地方创建子进程。这就是所谓的forking,它使用fork()函数:

            pid_t pid;/* Fork off the parent process */       pid = fork();if (pid < 0) {exit(EXIT_FAILURE);}/* If we got a good PID, thenwe can exit the parent process. */if (pid > 0) {exit(EXIT_SUCCESS);////避免儿子成为僵尸进程 父进程先退出   子进程就是后台进程了}

注意调用fork()之后的错误检查。在编写守护程序时,必须尽可能地编写防御代码。事实上,守护进程中有很大一部分代码只包含错误检查。

函数的作用是:返回子进程的进程id(PID)(不等于零),或者在失败时返回-1。如果进程不能派生子进程,那么守护进程应该在这里终止。

如果从fork()返回的PID成功,则父进程必须正常退出。PID >0 返回子进程的id 此时需要exit退出父进程,也避免儿进程成为僵尸进程。子进程就是后台进程了。对于没有见过它的人来说,这可能看起来很奇怪,但通过分叉,子进程将继续从代码中执行。

4.2更改文件模式掩码(Umask)

为了写入守护进程创建的任何文件(包括日志),必须更改文件模式掩码(umask),以确保它们可以正确写入或读取。这类似于从命令行运行umask,但我们在这里是通过编程实现的。我们可以使用umask()函数来实现这一点:

        pid_t pid, sid;/* Fork off the parent process */pid = fork();if (pid < 0) {/* Log failure (use syslog if possible) */exit(EXIT_FAILURE);}/* If we got a good PID, thenwe can exit the parent process. */if (pid > 0) {exit(EXIT_SUCCESS);}/* Change the file mode mask */umask(0);

通过将umask设置为0,我们可以完全访问守护进程生成的文件。即使您不打算使用任何文件,也最好在这里设置umask,以防您访问文件系统上的文件。

4.3打开日志进行书写

这部分是可选的,但建议您在系统中的某个位置打开日志文件进行写入。这可能是您可以查找有关守护进程的调试信息的唯一地方。

4.4创建唯一会话ID(SID)

从这里开始,子进程必须从内核获得唯一的SID才能运行。否则,子进程将成为系统中的孤立进程。上一节中声明的pid_t类型也用于为子进程创建新的SID:

        pid_t pid, sid;/* Fork off the parent process */pid = fork();if (pid < 0) {exit(EXIT_FAILURE);}/* If we got a good PID, thenwe can exit the parent process. */if (pid > 0) {exit(EXIT_SUCCESS);}/* Change the file mode mask */umask(0);/* Open any logs here *//* Create a new SID for the child process */sid = setsid();if (sid < 0) {/* Log any failure */exit(EXIT_FAILURE);}

同样,setsid()函数的返回类型与fork()相同。我们可以在这里应用相同的错误检查例程,以查看函数是否为子进程创建了SID。

4.5更改工作目录

当前的工作目录应该更改为保证始终存在的位置。由于许多Linux发行版并不完全遵循Linux文件系统层次结构标准,因此唯一保证存在的目录是根目录(/)。我们可以使用chdir()函数来实现这一点:

        pid_t pid, sid;/* Fork off the parent process */pid = fork();if (pid < 0) {exit(EXIT_FAILURE);}/* If we got a good PID, thenwe can exit the parent process. */if (pid > 0) {exit(EXIT_SUCCESS);}/* Change the file mode mask */umask(0);       /* Open any logs here */        /* Create a new SID for the child process */sid = setsid();if (sid < 0) {/* Log any failure here */exit(EXIT_FAILURE);}/* Change the current working directory */if ((chdir("/")) < 0) {/* Log any failure here */exit(EXIT_FAILURE);}

再一次,你可以看到防御性编码正在发生。chdir()函数在失败时返回-1,因此在更改到守护进程中的根目录后,一定要检查是否返回了-1。

4.6关闭标准文件描述符

设置守护进程的最后一步是关闭标准文件描述符(STDIN、STDOUT、STDERR)。由于守护进程无法使用终端,这些文件描述符是冗余的,存在潜在的安全隐患。

close()函数可以为我们处理这个问题:

        pid_t pid, sid;/* Fork off the parent process */pid = fork();if (pid < 0) {exit(EXIT_FAILURE);}/* If we got a good PID, thenwe can exit the parent process. */if (pid > 0) {exit(EXIT_SUCCESS);}/* Change the file mode mask */umask(0);       /* Open any logs here *//* Create a new SID for the child process */sid = setsid();if (sid < 0) {/* Log any failure here */exit(EXIT_FAILURE);}/* Change the current working directory */if ((chdir("/")) < 0) {/* Log any failure here */exit(EXIT_FAILURE);}/* Close out the standard file descriptors */close(STDIN_FILENO);close(STDOUT_FILENO);close(STDERR_FILENO);

坚持使用为文件描述符定义的常量是一个好主意,以实现系统版本之间的最大可移植性。

5.编写守护程序代码

5.1初始化

现在,您基本上已经告诉Linux您是一个守护程序,所以现在是时候编写实际的守护程序代码了。初始化是这里的第一步。因为这里可以调用许多不同的函数来设置守护进程的任务,所以我不会在这里深入讨论。

这里最重要的一点是,在初始化守护进程中的任何内容时,这里也适用相同的防御性编码准则。在写入系统日志或您自己的日志时,请尽可能详细。如果没有足够的关于守护进程状态的信息,调试守护进程可能会非常困难。

5.2大循环

守护进程的主代码通常位于无限循环中。从技术上讲,它不是一个无限循环,但它的结构是一个循环:

        pid_t pid, sid;/* Fork off the parent process */pid = fork();if (pid < 0) {exit(EXIT_FAILURE);}/* If we got a good PID, thenwe can exit the parent process. */if (pid > 0) {exit(EXIT_SUCCESS);}/* Change the file mode mask */umask(0);       /* Open any logs here *//* Create a new SID for the child process */sid = setsid();if (sid < 0) {/* Log any failures here */exit(EXIT_FAILURE);}/* Change the current working directory */if ((chdir("/")) < 0) {/* Log any failures here */exit(EXIT_FAILURE);}/* Close out the standard file descriptors */close(STDIN_FILENO);close(STDOUT_FILENO);close(STDERR_FILENO);/* Daemon-specific initialization goes here *//* The Big Loop */while (1) {/* Do some task here ... */sleep(30); /* wait 30 seconds */}

这种典型的循环通常是一个while循环,它有一个无限终止条件,在那里调用sleep使其以指定的间隔运行。

把它想象成心跳:当你的心跳时,它会执行一些任务,然后等待下一次心跳的发生。许多守护进程都遵循相同的方法。

6.把所有这些放在一起

6.1完整样品

下面列出的是一个完整的示例守护程序,它显示了设置和执行所需的所有步骤。要运行它,只需使用gcc编译,并从命令行开始执行。要终止,请在找到PID后使用kill命令。

我还加入了正确的include语句,用于与syslog进行接口,除了使用自己的日志进行fopen()/fwrite()/fclose()函数调用之外,建议至少发送start/stop/pause/die log语句。

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <syslog.h>
#include <string.h>int main(void) {/* Our process ID and Session ID */pid_t pid, sid;/* Fork off the parent process */pid = fork();if (pid < 0) {exit(EXIT_FAILURE);}/* If we got a good PID, thenwe can exit the parent process. */if (pid > 0) {exit(EXIT_SUCCESS);}/* Change the file mode mask */umask(0);/* Open any logs here */        /* Create a new SID for the child process */sid = setsid();if (sid < 0) {/* Log the failure */exit(EXIT_FAILURE);}/* Change the current working directory */if ((chdir("/")) < 0) {/* Log the failure */exit(EXIT_FAILURE);}/* Close out the standard file descriptors */close(STDIN_FILENO);close(STDOUT_FILENO);close(STDERR_FILENO);/* Daemon-specific initialization goes here *//* The Big Loop */while (1) {/* Do some task here ... */sleep(30); /* wait 30 seconds */}exit(EXIT_SUCCESS);
}

从这里,您可以使用这个框架来编写自己的守护进程。确保添加自己的日志(或使用syslog工具),并进行防御性编码、防御性编码、防御性编码!

Linux守护进程service Daemon 【C语言构建简单的守护进程】相关推荐

  1. 用C语言构建简单的石墨烯六边形模型(附带边界条件)

    一个非常简单的石墨烯模型构建,可以做一些小的分子动力学模拟.六边形模型很容易构造,关键是处理周期边界上的原子.可供物理学,材料学方面的本科生和硕士低年级参考. 效果图: 头文件head.h: #def ...

  2. 嵌入式linux系统下简单守护进程(daemon)的编写

    最近公司项目需要,需要在我们的嵌入式linux设备中创建一个守护进程,用于保护系统中的主进程,防止某些不可预期的意外导致主进程异常结束后,系统完全宕机没有任何反应,破坏用户体验感.但是,查阅诸多资料之 ...

  3. 【Linux】守护进程( Daemon)的定义,作用,创建流程

    守护进程( Daemon) 守护进程( Daemon) 1.定义 2.作用 3.创建流程 4.实例 参考 守护进程( Daemon) 1.定义 守护进程是运行在后台的一种特殊进程,它独立于控制终端并且 ...

  4. Linux C语言 创建一个简单的守护进程

    一.什么是守护进程?         首先我们先来简单了解一下什么是守护进程,守护进程在Linux中说白了就是一个后台进程,在后台默默服务,不受终端(会话)控制,生命周期长,在系统引导装入时启动,在系 ...

  5. SAP ABAP守护进程(ABAP Daemon)的实现方式

    Jerry本科学习<计算机操作系统>这门专业课时,了解到了守护进程的理念,当时我们是从Linux操作系统里的守护进程开始学习这个概念的:Linux守护进程是运行在后台的一种特殊进程,独立于 ...

  6. 守护进程(Daemon process)

    什么是守护进程? 守护进程(Daemon Process),也就是通常说的 Daemon 进程(精灵进程),是 Linux 中的后台服务进程.它是一个生存期较长的进程,通常独立于控制终端并且周期性地执 ...

  7. Linux中编写简单的守护进程

    1.守护进程概述 守护进程就是通常所说的daemon进程,他是linux中的后台服务进程.他是一个生存期很长的进程,通常独立于控制终端并且周期性的执行某种任务,或等待处理魔种发生的事件.守护进程通常在 ...

  8. 《嵌入式Linux与物联网软件开发——C语言内核深度解析》一2.4 位运算构建特定二进制数...

    本节书摘来自异步社区<嵌入式Linux与物联网软件开发--C语言内核深度解析>一书中的第2章,第2.4节,作者朱有鹏 , 张先凤,更多章节内容可以访问云栖社区"异步社区" ...

  9. 守护进程(Daemon)

    守护进程(Daemon):Daemon是一种特殊进程,脱离终端.可以避免进程被任何终端所产生的信号打断,在执行过程中所产生的信息也不在任何终端上显示. 守护进程可以通过以下方式启动: 1:在系统启动时 ...

最新文章

  1. torch.nn.functional.pad(input, pad, mode=‘constant‘, value=0)
  2. Native snappy library not available: this version of libhadoop was built without snappy support
  3. Linux 常用的软件包管理器/软件包管理工具
  4. iOS (封装)一句话调用系统的alertView和alertController
  5. mysql循环遍历获取_MySQL 全表遍历
  6. vml入门教程 【转】
  7. 原生JS操作DOM对象
  8. AcWing进阶算法课Level-4 第六章 搜索 (模拟退火,爬山)
  9. 如何使用 Cisdem Video Converter 在 Mac 上将 MOV 转换为 MP3
  10. java-判断集合中的某个元素的属性是否全部相同
  11. 解决新版edge浏览器首页被搜狗、haoqq等垃圾搜索引擎捆绑问题,并将启动首页设为edge自带新标签页
  12. 和极有家一起玩转智能家居——极有家未来之家合作招募
  13. 基于Python的招聘推荐与薪资预测系统的设计与实现
  14. Python3制作二维码
  15. Wayland/Weston 启动方式简介
  16. 查看linux系统CPU内存
  17. 安卓手机格式化怎么弄_安卓手机怎样进入格式化?
  18. Extjs 3.0.0 问题总结
  19. layui表格取值赋值
  20. linux 查看进程 发包,Linux网络发包流程

热门文章

  1. c++ primer plus 第六版第十七章学习笔记
  2. python做视频特效_Python实现高端平民电影特效
  3. 监理工程师报考条件及专业要求
  4. Ralink SDK wifi相关调试指令
  5. ftp服务器PPT文件复制不了,FTP服务器的使用.ppt
  6. 306端口占用问题(windows)
  7. openjdk和jdk的区别与联系
  8. 会声会影2020免费注册序列号
  9. phpize 编译安装 PHP 加速器 APC
  10. 在“提示”框中:管理Android音频配置文件,Android上的Google书签和电缆固定