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,一经查实,立即删除!

相关文章

视频号直播弹幕采集

系列文章目录 websocket逆向http拦截websocket拦截视频号直播弹幕采集 系列文章目录前言技术分析分析技术选择前提准备事件分析消息去重用户进房用户发言用户送礼用户点赞用户唯一id前言 很多小伙伴倒在了礼物事件,还有用户唯一标识下。 本篇文章将讲解视频号直播弹幕的获取的…

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;将文法规则中的句子逐…

python内置模块winreg,以及使用winreg模块获取所有当前windows电脑已安装应用的安装信息

winreg模块 进入系统注册表的方法多种多样,最常见的就是运行窗口输入命令“regedit”,即可进入注册表,而Python的winreg模块可以对注册表进行一系列操作 "winreg"中的各个常量 注册表地址(HKEY_ )常量 winreg.HKEY_CLASSES_ROOT #存储应用和shell的信息 winreg…

用 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…

在 Azure 中开发云原生应用程序:工具和技巧

Azure 中的云原生开发工具 Azure 包含一系列用于云原生应用程序开发的内置工具和服务。这里介绍的服务和工具是很好的入门选择。 发展 Azure 包括两个用于开发和构建云原生应用程序的主要工具&#xff1a;Visual Studio (VS) 和Azure应用服务。 VS 是一个集成开发环境&#…

【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;我们可以…

[C++ 网络协议] IOCP(Input Output Completion Port)

1.什么是IOCP IOCP&#xff08;Input Output Completion Port&#xff09;输入输出完成端口。其实就是基于重叠I/O的一种改进的模型。 重叠I/O具有缺点&#xff1a;重复调用非阻塞模式的accpet函数和以进入alertablewait状态为目的的SleepEx函数会影响程序性能。 而IOCP提供…

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

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

环形缓冲RingBuffer和无锁

环形缓冲 环形缓冲区&#xff0c;也被称为循环缓冲区或者环形队列&#xff0c;是一种数据结构类型&#xff0c;它在内存中形成一个环形的存储空间。环形缓冲区的特点是其终点和起点是相连的&#xff0c;形成一个环状结构。这种数据结构在处理流数据和实现数据缓存等场景中具有…

【MySQL】内置函数——日期函数

函数名称描述current_date()当前日期current_time()当前时间current_timestamp()当前时间戳date(datetime)返回datetime的日期部分date_add(date,interval d_value_type)在date中添加日期或时间。interval后的数值可以是&#xff1a;year&#xff0c;day&#xff0c;minute&…

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

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

java学习--day22(进程线程)

文章目录 1.什么是进程2.什么是线程3.线程和进程的区别【面试题】4.并发和并行5.创建线程的两种方式【重点】1.继承Thread2.实现Runnable接口 6.线程下面的几个方法7.线程的同步和锁【重要】 1.什么是进程 是独立的运行程序 ​ 比如咱们电脑软件&#xff0c;你启动起来以后&…

Ubuntu LabelMe AI 识别

1.创建虚拟环境 conda create -n labelme python3.9 2.激活虚拟环境 conda activate labelme 3.安装labelme pip install pyqt5 -i https://pypi.tuna.tsinghua.edu.cn/simple pip install pillow -i https://pypi.tuna.tsinghua.edu.cn/simple pip install labelme -i ht…