Linux 守护进程

一 何为守护进程

守护进程( Daemon )也称为精灵进程,是运行在后台的一种特殊进程,它独立于控制终端并且周期性
地执行某种任务或等待处理某些事情的发生,主要表现为以下两个特点:
  • 长期运行。守护进程是一种生存期很长的一种进程,它们一般在系统启动时开始运行,除非强行终 止,否则直到系统关机都会保持运行。与守护进程相比,普通进程都是在用户登录或运行程序时创 建,在运行结束或用户注销时终止,但守护进程不受用户登录注销的影响,它们将会一直运行着、 直到系统关机。
  •  与控制终端脱离。Linux 中,系统与用户交互的界面称为终端,每一个从终端开始运行的进程都 会依附于这个终端,这是上一小节给大家介绍的控制终端,也就是会话的控制终端。当控制终端被 关闭的时候,该会话就会退出,由控制终端运行的所有进程都会被终止,这使得普通进程都是和运 行该进程的终端相绑定的;但守护进程能突破这种限制,它脱离终端并且在后台运行,脱离终端的 目的是为了避免进程在运行的过程中的信息在终端显示并且进程也不会被任何终端所产生的信息 所打断。 守护进程是一种很有用的进程。Linux 中大多数服务器就是用守护进程实现的,譬如,Internet 服务器 inetdWeb 服务器 httpd 等。同时,守护进程完成许多系统任务,譬如作业规划进程 crond 等。 守护进程 Daemon,通常简称为 d,一般进程名后面带有 d 就表示它是一个守护进程。守护进程与终端 无任何关联,用户的登录与注销与守护进程无关、不受其影响,守护进程自成进程组、自成会话,即 pid=gid=sid。通过命令"ps -ajx"查看系统所有的进程,如下所示

TTY 一栏是问号?表示该进程没有控制终端,也就是守护进程,其中 COMMAND 一栏使用中括号 [] 括 起来的表示内核线程,这些线程是在内核里创建,没有用户空间代码,因此没有程序文件名和命令行,通常 采用 k 开头的名字,表示 Kernel

二 编写守护进程程序

如何将自己编写的程序运行之后变成一个守护进程呢?本小节就来学习如何编写守护进程程序,编写
守护进程一般包含如下几个步骤:
1) 创建子进程、终止父进程
父进程调用 fork() 创建子进程,然后父进程使用 exit() 退出,这样做实现了下面几点。第一,如果该守护 进程是作为一条简单地 shell 命令启动,那么父进程终止会让 shell 认为这条命令已经执行完毕。第二,虽然 子进程继承了父进程的进程组ID ,但它有自己独立的进程 ID ,这保证了子进程不是一个进程组的组长进程, 这是下面将要调用 setsid 函数的先决条件
2) 子进程调用 setsid 创建会话
这步是关键,在子进程中调用上一小节给大家介绍的 setsid() 函数创建新的会话,由于之前子进程并不 是进程组的组长进程,所以调用 setsid() 会使得子进程创建一个新的会话,子进程成为新会话的首领进程, 同样也创建了新的进程组、子进程成为组长进程,此时创建的会话将没有控制端。
所以这里调用 setsid 有 三个作用:让子进程摆脱原会话的控制、让子进程摆脱原进程组的控制和让子进程摆脱原控制终端的控制。 在调用 fork 函数时,子进程继承了父进程的会话、进程组、控制终端等,虽然父进程退出了,但原先 的会话期、进程组、控制终端等并没有改变,因此,那还不是真正意义上使两者独立开来。setsid 函数能够 使子进程完全独立出来,从而脱离所有其他进程的控制。
3) 将工作目录更改为根目录
子进程是继承了父进程的当前工作目录,由于在进程运行中,当前目录所在的文件系统是不能卸载的, 这对以后使用会造成很多的麻烦。因此通常的做法是让“/ ”作为守护进程的当前目录,当然也可以指定其 它目录来作为守护进程的工作目录。
4) 重设文件权限掩码 umask
文件权限掩码 umask 用于对新建文件的权限位进行屏蔽,在 5.5.5 小节中有介绍。由于使用 fork 函数新 建的子进程继承了父进程的文件权限掩码,这就给子进程使用文件带来了诸多的麻烦。因此, 把文件权限掩 码设置为 0,确保子进程有最大操作权限、这样可以大大增强该守护进程的灵活性。设置文件权限掩码的函 数是 umask ,通常的使用方法为 umask(0)

 umask(user file-creatiopn mode mask)是linux中的一个命令,用于为用户文件创建权限掩码,语法“umask [-S][权限掩码]”;其中,“权限掩码”是由3个八进制的数字所组成,将现有的存取权限减掉权限掩码后,即可产生建立文件时预设的权限。

/umask命令可确定要在创建的任何文件或者目录上设置的默认权限。umask命令为用户文件创建掩码,,是创建文件或文件夹时默认权限的基础。通常我们可以使用chmod修改linux中文件的权限.umask的作用与chmod的效果相反,具体看下面。

若没有文件掩码时,文件的默认权限为0666,文件夹的默认权限为0777。

5) 关闭不再需要的文件描述符
子进程继承了父进程的所有文件描述符,这些被打开的文件可能永远不会被守护进程(此时守护进程指 的就是子进程,父进程退出、子进程成为守护进程)读或写,但它们一样消耗系统资源,可能导致所在的文 件系统无法卸载,所以必须关闭这些文件,这使得守护进程不再持有从其父进程继承过来的任何文件描述 符。
6) 将文件描述符号为 0 1 2 定位到 /dev/null
将守护进程的标准输入、标准输出以及标准错误重定向到 /dev/null ,这使得守护进程的输出无处显示、 也无处从交互式用户那里接收输入。
7) 其它:忽略 SIGCHLD 信号
处理 SIGCHLD 信号不是必须的,但对于某些进程,特别是并发服务器进程往往是特别重要的,服务器 进程在接收到客户端请求时会创建子进程去处理该请求,如果子进程结束之后,父进程没有去 wait 回收子 进程,则子进程将成为僵尸进程;如果父进程 wait 等待子进程退出,将又会增加父进程的负担、也就是增 加服务器的负担,影响服务器进程的并发性能,在 Linux 下,可以将 SIGCHLD 信号的处理方式设置为 SIG_IGN,也就是忽略该信号,可让内核将僵尸进程转交给 init 进程去处理,这样既不会产生僵尸进程、又 省去了服务器进程回收子进程所占用的时间。

三 示例

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>// 文件权限掩码 umask 用于对新建文件的权限位进行屏蔽,在 5.5.5 小节中有介绍。由于使用 fork 函数新
// 建的子进程继承了父进程的文件权限掩码,这就给子进程使用文件带来了诸多的麻烦。因此,把文件权限掩
// 码设置为 0,确保子进程有最大操作权限、这样可以大大增强该守护进程的灵活性。设置文件权限掩码的函
// 数是 umask,通常的使用方法为 umask(0)// umask(user file-creatiopn mode mask)是linux中的一个命令,用于为用户文件创建权限掩码,语法“umask [-S][权限掩码]”;其中,“权限掩码”是由3个八进制的数字所组成,将现有的存取权限减掉权限掩码后,即可产生建立文件时预设的权限。// umask命令可确定要在创建的任何文件或者目录上设置的默认权限。umask命令为用户文件创建掩码,,是创建文件或文件夹时默认权限的基础。通常我们可以使用chmod修改linux中文件的权限.umask的作用与chmod的效果相反,具体看下面。// 若没有文件掩码时,文件的默认权限为0666,文件夹的默认权限为0777。int main(void)
{pid_t pid;int i;/* 创建子进程 */pid = fork();if (0 > pid){perror("fork error");exit(-1);}else if (0 < pid) // 父进程exit(0);      // 直接退出/**子进程*//* 1.创建新的会话、脱离控制终端 */if (0 > setsid()){perror("setsid error");exit(-1);}/* 2.设置当前工作目录为根目录 */if (0 > chdir("/")){perror("chdir error");exit(-1);}/* 3.重设文件权限掩码 umask */umask(0);/* 4.关闭所有文件描述符 */for (i = 0; i < sysconf(_SC_OPEN_MAX); i++)close(i);/* 5.将文件描述符号为 0、1、2 定位到/dev/null */open("/dev/null", O_RDWR);// 回到dup函数,这个函数有一个参数就是文件描述符, 这个函数创建出一个新的文件描述符,这个文件描述符与参数中的这个文件描述符指向同一个文件, 而且新的文件描述符总是取系统中最小的的整数值dup(0);dup(0);/* 6.忽略 SIGCHLD 信号 */signal(SIGCHLD, SIG_IGN);/* 正式进入到守护进程 */for (;;){sleep(1);puts("守护进程运行中......");}exit(0);
}
示例代码中其中第 4 步中调用 sysconf(_SC_OPEN_MAX) 用于获取当前系统允许进程打开的最大文件数量。
我们在守护进程中添加了死循环,每隔 1 秒钟打印一行字符串信息,接下来编译运行:
gcc -o daemon_process daemon_process.c 

运行之后,没有任何打印信息输出,原因在于守护进程已经脱离了控制终端,它的打印信息并不会输出
显示到终端,在代码中已经将标准输入、输出以及错误重定位到了/dev/null,/dev/null 是一个黑洞文件,自然是看不到输出信息。
使用"ps -ajx"命令查看进程,如下所示:

3.1 文件重定向 dup2

上述文件重定向部分 也可用dup2实现

// 5、重定向0,1,2if ((fd == open("/dev/null", O_RDWR) != -1)) // fd == 3{dup2(fd, STDIN_FILENO);dup2(fd, STDOUT_FILENO);dup2(fd, STDERR_FILENO);// 6、关闭掉不需要的fdif (fd > STDERR_FILENO)close(fd);}

dup2(3, 2);  让2号文件描述符重定向到 log.txt,其实就是把原本3号描述符保存的地址拷贝到2号描述符的位置。、

例子:

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>int main(){int fd = open("log.txt", O_CREAT | O_RDWR, 0644);if(fd < 0){perror("open");}dup2(fd, 1);                      // 文件重定向printf("newfd: hello, world\n");  // 向1号文件描述符写入内容const char* buf = "oldfd: hello, world\n";write(fd, buf, strlen(buf));      // 向原本的log.txt对应的文件描述符写入内容return 0; 
}

3.2 如何输出守护进程log到固定文件

解决办法如下:我们在log.hpp打印日志文件那,用宏定义一个serverTcp.log文件。

利用open函数打开此文件,返回到logFd 利用dup2把标准输入,标准输出重定向到logFd文件

注意 输出实时性。

 s y n c只是将所有修改过的块的缓存排入写队列,然后就返回,它并不等待实际I / O操作结束。 系统精灵进程(通常称为u p d a t e )一般每隔3 0秒调用一次s y n c函数。这就保证了定期刷新内 核的块缓存。命令s y n c ( 1 )也调用s y n c函数。
函数f s y n c只引用单个文件(由文件描述符f i l e d e s指定),它等待I / O结束,然后返回。f s y n c可/用于数据库这样的应用程序,它确保修改过的块立即写到磁盘上。比较一下f s y n c和O _ S Y N C标 志(见3 . 1 3节)。当调用f s y n c时,它更新文件的内容,而对于O _ S Y N C,则每次对文件调用w r i t e函数时就更新文件的内容。


 fflush和fsync的联系和区别
 [zz ] http://blog.chinaunix.net/u2/73874/showart_1421917.html

1.提供者fflush是libc.a中提供的方法,fsync是系统提供的系统调用。2.原形fflush接受一个参数FILE *.fflush(FILE *);fsync接受的时一个Int型的文件描述符。fsync(int fd);3.功能fflush:是把C库中的缓冲调用write函数写到磁盘[其实是写到内核的缓冲区]。fsync:是把内核缓冲刷到磁盘上。

 c库缓冲-----fflush---------〉内核缓冲--------fsync-----〉磁盘

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/99216.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

gitlab登录出现的Invalid login or password问题

前提 我是在一个项目里创建的gitlab账号&#xff0c;想在别的项目里登录或者官网登录发现怎么都登陆不上 原因 在GitLab中&#xff0c;有两种不同的账号类型&#xff1a;项目账号和个人账号&#xff08;官网账号&#xff09;。 项目账号&#xff1a;项目账号是在特定GitLab…

某果的一个小参数分析

分析链接:aHR0cHM6Ly9hcHBsZWlkLmFwcGxlLmNvbS9hY2NvdW50 分析目标&#xff1a;X-Apple-I-Fd-Client-Info 1.在浏览器搜索关键词&#xff0c;打下断点 我们再里面进行搜索&#xff0c;定位到这个位置&#xff0c;可以看到X-Apple-I-FD-Client-Info这个参数等于e&#xff0c;…

【C++设计模式之解释器模式:行为型】分析及示例

简介 解释器模式&#xff08;Interpreter Pattern&#xff09;是一种行为型设计模式&#xff0c;它提供了一种解决问题的方法&#xff0c;通过定义语言的文法规则&#xff0c;解释并执行特定的语言表达式。 解释器模式通过使用表达式和解释器&#xff0c;将文法规则中的句子逐…

用 HTTP 提交数据,基本就这 5 种方式

网页开发中&#xff0c;向服务端提交数据是一个基本功能&#xff0c;工作中会大量用 xhr/fetch 的 api 或者 axios 这种封装了一层的库来做。 可能大家都写过很多 http/https 相关的代码&#xff0c;但是又没有梳理下它们有哪几种呢&#xff1f; 其实通过 http/https 向服务端…

VBox启动失败、Genymotion启动失败、Vagrant迁移

VBox启动失败、Genymotion启动失败、Vagrant迁移 2023.10.9 最新版本vbox7.0.10、Genymotion3.5.0 Vbox启动失败 1、查看日志 Error -610 in supR3HardenedMainInitRuntime! (enmWhat4) Failed to locate ‘vcruntime140.dll’ 日志信息查看方法->找到虚拟机所在位置->…

对于L1正则化和L2正则化的理解

在DL中&#xff0c;L1和L2正则化经常被使用到&#xff0c;因为大于1L的正则化都是凸优化的问题&#xff0c;是个简单问题&#xff0c;可以被解决。 首先说正则的意义&#xff1a; 一切可以缓解过拟合的方法&#xff0c;都可以被叫做正则化 我最开始理解正则化的时候就是看lh…

【Bond随你温故Azure Architecture】之HADR篇

上次复盘数据保护策略还是在《数据需要找回怎么办&#xff1f;我们如何选择正确的恢复/退回方式&#xff1f;》探讨了在application&DB层面上&#xff0c;不同level的数据保护有不同策略。而它也恰好是今天HA&DR版图的一角&#xff08;RDBMS部分&#xff09;&#xff0…

CI/CD工具中的CI和CD的含义

CI/CD工具中的CI和CD的含义&#xff1f; CI/CD 是现代软件开发方法中广泛使用的一种方法。其中&#xff0c;CI 代表持续集成&#xff08;Continuous Integration&#xff09;&#xff0c;CD 则有两层含义&#xff0c;一是持续交付&#xff08;Continuous Delivery&#xff09;…

.net framework中webapi使用swagger进行接口文档展示

第一步&#xff1a;在nuget程序包管理中搜索“Swashbuckle”包&#xff0c;然后进行安装&#xff08;注&#xff1a;如果是.net core api请安装Sawshbuckle aspnetcore&#xff09;。 第二步&#xff1a;打开项目App_Start文件夹&#xff0c;修改SwaggerConfig.cs配置文件 我这…

mp4视频太大怎么压缩变小?

mp4视频太大怎么压缩变小&#xff1f;确实&#xff0c;很多培训和教学都转向了线上模式&#xff0c;这使得我们需要下载或分享大量的在线教学视频。然而&#xff0c;由于MP4视频文件通常较大&#xff0c;可能会遇到无法打开或发送的问题。为了解决这个问题&#xff0c;我们可以…

聊聊分布式架构02——Http到Https

目录 HTTP通信协议 请求报文 响应报文 持久连接 状态管理 HTTPS通信协议 安全的HTTPS HTTP到HTTPS的演变 对称加密 非对称加密 混合加密机制 证书机构 SSL到底是什么 HTTPS是身披SSL外壳的HTTP HTTP通信协议 一次HTTP请求的通信流程&#xff1a;客户端浏览器通过…

【Linux升级之路】7_进程信号

目录 一、【Linux初阶】信号入门 | 信号基本概念信号产生核心转储二、【Linux初阶】信号入门2 | 信号阻塞、捕捉、保存 一、【Linux初阶】信号入门 | 信号基本概念信号产生核心转储 链接&#xff1a; 【Linux初阶】信号入门 | 信号基本概念信号产生核心转储 二、【Linux初阶】…

【数据结构-字符串 三】【字符串转换】字符串解码

废话不多说&#xff0c;喊一句号子鼓励自己&#xff1a;程序员永不失业&#xff0c;程序员走向架构&#xff01;本篇Blog的主题是【字符串转换】&#xff0c;使用【字符串】这个基本的数据结构来实现&#xff0c;这个高频题的站点是&#xff1a;CodeTop&#xff0c;筛选条件为&…

RPC分布式网络通信框架项目

文章目录 对比单机聊天服务器、集群聊天服务器以及分布式聊天服务器RPC通信原理使用Protobuf做数据的序列化&#xff0c;相比较于json&#xff0c;有哪些优点&#xff1f;环境配置使用项目代码工程目录vscode远程开发Linux项目muduo网络库编程示例CMake构建项目集成编译环境Lin…

【计算机网络黑皮书】传输层

【事先声明】 这是对于中科大的计算机网络的网课的学习笔记&#xff0c;感谢郑烇老师的无偿分享 书籍是《计算机网络&#xff08;自顶向下方法 第6版&#xff09;》 需要的可以私信我&#xff0c;无偿分享&#xff0c;课程简介下也有 课程链接 目录 传输服务与协议网络层与传输…

常见排序算法Java版(待续)

冒泡排序O(n^2) public class Main {public static void main(String[] args) {Random random new Random();int[] nums new int[]{random.nextInt(100), random.nextInt(100), random.nextInt(100), random.nextInt(100), random.nextInt(100), random.nextInt(100)};for (i…

英特尔参与 CentOS Stream 项目

导读红帽官方发布公告欢迎英特尔参与进 CentOS Stream 项目&#xff0c;并表示 “这一举措不仅进一步深化了我们长期的合作关系&#xff0c;也构建在英特尔已经在 Fedora 项目中积极贡献的基础之上。” 目前&#xff0c;CentOS Stream 共包括以下特别兴趣小组&#xff08;SIG&a…

汽车冲压车间的RFID技术设计解决方案

一、RFID技术的基本原理 RFID技术是一种利用非接触式自动识别的技术&#xff0c;通过将RFID标签放置在被识别物品上&#xff0c;并使用RFID读写器对标签进行扫描和识别&#xff0c;实现对物品的自动识别和追踪。RFID标签分为被动式和主动式两种。被动式标签无内置电源&#xf…

23.3 Bootstrap 框架4

1. 轮播 1.1 轮播样式 在Bootstrap 5中, 创建轮播(Carousel)的相关类名及其介绍: * 1. carousel: 轮播容器的类名, 用于标识一个轮播组件. * 2. slide: 切换图片的过渡和动画效果. * 3. carousel-inner: 轮播项容器的类名, 用于包含轮播项(轮播图底下椭圆点, 轮播的过程可以显…

HTTP协议的请求协议和响应协议的组成,HTTP常见的状态信息

HTTP协议 什么是协议 协议实际上是某些人或组织提前制定好的一套规范,大家只要都按照这个规范来就可以做到沟通无障碍 HTTP协议是W3C(万维网联盟组织)制定的一种超文本传输通信协议(发送消息的模板和数据的格式),除了传送字符串,还有声音、视频、图片等流媒体等超文本信息 …