服务器守护进程化
目录
一、守护进程的定义与特点
1、定义
2、特点
二、守护进程的原理
三、守护进程与会话(Session)的关系
四、C++实现守护进程
守护进程(Daemon Process)是一个在后台运行、通常不与用户直接交互的进程。守护进程是操作系统中非常重要的一部分,常见的应用包括系统日志、网络服务、数据库管理等。在这篇博客中,我们将详细探讨守护进程的原理、如何与会话管理联系,并通过C++实现一个简单的守护进程。将服务器守护进程化的主要目的是确保服务器在后台持续运行,并在意外崩溃或重启后自动恢复。这样可以使服务在没有人工干预的情况下长期稳定运行,并减少系统管理的复杂度。
一、守护进程的定义与特点
1、定义
守护进程是一个没有终端控制的进程,它通常在系统启动时启动,独立于任何用户会话(session),并且在后台持续运行。守护进程的特点是它不依赖于用户的输入输出,运行时不会产生终端交互。
2、特点
- 后台运行:守护进程通常在操作系统启动时启动,或者在用户登录后由系统服务启动,并在后台持续运行。
- 无终端:守护进程不与任何终端或用户会话关联,它通常不与标准输入输出(stdin, stdout, stderr)相关联。
- 独立性:守护进程与用户的登录会话是独立的,它在后台静静运行,执行系统级任务,如日志记录、定时任务、文件清理等。
- 父进程为init进程:守护进程在系统启动时由父进程(通常是init进程)启动,运行时不会退出。
- PID(进程ID):守护进程的PID是由操作系统分配的,它通常会被写入到某个文件中以供后续管理和终止。
二、守护进程的原理
守护进程是通过脱离控制终端、使自己成为一个独立的后台进程来实现的。这是通过几个步骤实现的:
-
创建子进程:守护进程首先会创建一个子进程,父进程退出,子进程继续执行,这样可以让守护进程避免与任何用户会话或终端直接交互。
-
创建新的会话(Session):守护进程通常会调用
setsid()系统调用创建一个新的会话,成为该会话的首进程。新会话的创建意味着它不再与原始的控制终端和进程组相关联。 -
改变工作目录:守护进程通常会调用
chdir()来更改工作目录。为了避免占用终端的目录,守护进程通常会将工作目录更改为/。 -
关闭文件描述符:守护进程还会关闭与终端相关的文件描述符,包括标准输入(stdin)、标准输出(stdout)、标准错误(stderr)。通常会将它们重定向到
/dev/null,以防止输出到终端。 -
忽略信号:守护进程会设置适当的信号处理,避免因收到如SIGHUP等信号导致进程退出。
void Daemon(const std::string &cwd = "")
{// 1. 忽略其他异常信号 signal(SIGCLD, SIG_IGN);signal(SIGPIPE, SIG_IGN);signal(SIGSTOP, SIG_IGN);// 2. 将自己变成独立的会话if (fork() > 0)//>0说明是父进程,让父进程直接退出exit(0);setsid(); //子进程// 3. 更改当前调用进程的工作目录if (!cwd.empty())chdir(cwd.c_str());// 4. 标准输入,标准输出,标准错误重定向至/dev/null 垃圾桶int fd = open(nullfile.c_str(), O_RDWR);if(fd > 0){dup2(fd, 0);dup2(fd, 1);dup2(fd, 2);close(fd);}
}
三、守护进程与会话(Session)的关系
会话(Session)是与进程、终端和进程组密切相关的概念。会话的作用是管理一组相关的进程。
-
会话的创建:每个登录的用户会话都有一个会话ID(Session ID),一个会话可以有多个进程组(Process Group),而每个进程组中的进程共享同一个控制终端。
-
脱离控制终端:守护进程通过
setsid()系统调用来脱离当前会话及其控制终端,成为一个新的会话的首进程。这样,守护进程就不再与任何终端关联,它可以自由地运行而不受用户的控制。 -
控制终端:一旦守护进程创建了新的会话并成为首进程,它就不再与任何控制终端关联。控制终端通常与用户的登录会话相关联,但守护进程会断开这一关系,避免终端输入或输出干扰其运行。
-
进程组与信号处理:会话中的进程通常共享进程组,而进程组的控制由会话首进程管理。守护进程通常会设置信号处理机制,使其能够管理来自进程组的信号。
四、C++实现守护进程
#pragma once#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <signal.h>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>const std::string nullfile = "/dev/null";void Daemon(const std::string &cwd = "")
{// 1. 忽略其他异常信号 signal(SIGCLD, SIG_IGN);signal(SIGPIPE, SIG_IGN);signal(SIGSTOP, SIG_IGN);// 2. 将自己变成独立的会话if (fork() > 0)//>0说明是父进程,让父进程直接退出exit(0);setsid(); //子进程// 3. 更改当前调用进程的工作目录if (!cwd.empty())chdir(cwd.c_str());// 4. 标准输入,标准输出,标准错误重定向至/dev/null 垃圾桶int fd = open(nullfile.c_str(), O_RDWR);if(fd > 0){dup2(fd, 0);dup2(fd, 1);dup2(fd, 2);close(fd);}
}
#pragma once#include <iostream>
#include <string>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
#include <signal.h>
#include <signal.h>
#include "Log.hpp"
#include "ThreadPool.hpp"
#include "Task.hpp"
#include "Daemon.hpp"const int defaultfd = -1;
const std::string defaultip = "0.0.0.0";
const int backlog = 10; // 但是一般不要设置的太大
extern Log lg;enum
{UsageError = 1,SocketError,BindError,ListenError,
};class TcpServer;class ThreadData
{
public:ThreadData(int fd, const std::string &ip, const uint16_t &p, TcpServer *t): sockfd(fd), clientip(ip), clientport(p), tsvr(t){}
public:int sockfd;std::string clientip;uint16_t clientport;TcpServer *tsvr;
};class TcpServer
{
public:TcpServer(const uint16_t &port, const std::string &ip = defaultip) : listensock_(defaultfd), port_(port), ip_(ip){}void InitServer(){listensock_ = socket(AF_INET, SOCK_STREAM, 0);if (listensock_ < 0){lg(Fatal, "create socket, errno: %d, errstring: %s", errno, strerror(errno));exit(SocketError);}lg(Info, "create socket success, listensock_: %d", listensock_);int opt = 1;setsockopt(listensock_, SOL_SOCKET, SO_REUSEADDR|SO_REUSEPORT, &opt, sizeof(opt)); // 防止偶发性的服务器无法进行立即重启(tcp协议的时候再说)struct sockaddr_in local;memset(&local, 0, sizeof(local));local.sin_family = AF_INET;local.sin_port = htons(port_);inet_aton(ip_.c_str(), &(local.sin_addr));// local.sin_addr.s_addr = INADDR_ANY;if (bind(listensock_, (struct sockaddr *)&local, sizeof(local)) < 0){lg(Fatal, "bind error, errno: %d, errstring: %s", errno, strerror(errno));exit(BindError);}lg(Info, "bind socket success, listensock_: %d", listensock_);// Tcp是面向连接的,服务器一般是比较“被动的”,服务器一直处于一种,一直在等待连接到来的状态if (listen(listensock_, backlog) < 0){lg(Fatal, "listen error, errno: %d, errstring: %s", errno, strerror(errno));exit(ListenError);}lg(Info, "listen socket success, listensock_: %d", listensock_);}void Start(){Daemon();ThreadPool<Task>::GetInstance()->Start();// for fork();// signal(SIGCHLD, SIG_IGN);lg(Info, "tcpServer is running....");for (;;){// 1. 获取新连接struct sockaddr_in client;socklen_t len = sizeof(client);int sockfd = accept(listensock_, (struct sockaddr *)&client, &len);if (sockfd < 0){lg(Warning, "accept error, errno: %d, errstring: %s", errno, strerror(errno)); //?continue;}uint16_t clientport = ntohs(client.sin_port);char clientip[32];inet_ntop(AF_INET, &(client.sin_addr), clientip, sizeof(clientip));// version 4 --- 线程池版本Task t(sockfd, clientip, clientport);ThreadPool<Task>::GetInstance()->Push(t);}}~TcpServer() {}private:int listensock_;uint16_t port_;std::string ip_;
};


表示服务已经启动
相关文章:
服务器守护进程化
目录 一、守护进程的定义与特点 1、定义 2、特点 二、守护进程的原理 三、守护进程与会话(Session)的关系 四、C实现守护进程 守护进程(Daemon Process)是一个在后台运行、通常不与用户直接交互的进程。守护进程是操作系统中…...
灵途科技亮相2024世界传感器大会 分享光纤光源技术突破
12月1日至2日,2024世界传感器大会(WSS)在郑州国际会展中心隆重举办,泛自动驾驶领域光电感知专家灵途科技受邀参加“光纤传感器与激光雷达”分论坛,并在大会上带来《激光雷达用一体化光纤光源》专题演讲,同与…...
day35—蓝桥杯2024年第16届校赛模拟第二期-T4(最小花费)
【问题描述】 小蓝有一个整数,初始值为 1 ,他可以花费一些代价对这个整数进行变换。 小蓝可以花费 1 的代价将整数增加 1 。 小蓝可以花费 3 的代价将整数增加一个值,这个值是整数的数位中最大的那个(1 到 9)。 小蓝可…...
【CSS in Depth 2 精译_068】11.2 颜色的定义(下):CSS 中的各种颜色表示法简介
当前内容所在位置(可进入专栏查看其他译好的章节内容) 第四部分 视觉增强技术 ✔️【第 11 章 颜色与对比】 ✔️ 11.1 通过对比进行交流 11.1.1 模式的建立11.1.2 还原设计稿 11.2 颜色的定义 11.2.1 色域与色彩空间11.2.2 CSS 颜色表示法 ✔️ 11.2.2.…...
游戏引擎学习第38天
仓库: https://gitee.com/mrxiao_com/2d_game 回顾上次的内容。 我们之前讨论了将精灵放在屏幕上,但颜色错误的问题。问题最终查明是因为使用了一个调整工具,导致文件的字节顺序发生了变化。重新运行“image magic”工具对一些大图像进行重新处理后&am…...
P1223 排队接水(贪心)
题目描述 有 𝑛个人在一个水龙头前排队接水,假如每个人接水的时间为 𝑇𝑖,请编程找出这 𝑛 个人排队的一种顺序,使得 𝑛个人的平均等待时间最小。 输入格式 第一行为一个整数 &am…...
关于springBoot+vue项目中配置SSL证书问题
前端可以通过https进行访问 1.前端在访问后端接口时,使用https进行访问,在request.js配置文件中,这个文件是配置axios的基本请求的,在基础请求地址中改为https方式 2.需要在Linux中的nginx中配置ssl证书,具体请参考&…...
GUI的最终选择:Tkinter
Tkinter是Python默认的GUI库,因此使用时直接导入即可:import tkinter 17.1 Tkinter之初体验 代码分析: tkinter.mainloop()通常是程序的最后一行代码,执行后程序进入主事件循环。 17.2 进阶版本 将代码封装成类: 运…...
Photohop关于数位板没有压力感,PS画笔的钢笔压力总是显示感叹号的问题解放方法
(实际我只用到红色字2步解决了问题,但为了兼顾更多朋友,还是把其他步骤详细完善) 一,先确定数位板正常链接电脑,并安装好驱动,并在驱动测试到压力 二,解决PS前感叹号问题 …...
rust websocket Echo server高性能服务器开发
最近在学习websocket时,一直没有发现好的websocket server工具来调试,于是就自己做了一个websocket server用来学习和调试。因为rust性能遥遥领先,所以就采用了rust来搭建服务器。废话不多说直接上代码main.rs: use tokio::net::TcpListener; use tokio_tungstenite::tung…...
19、网络编程:
19、网络编程: 网络的相关概念: 网络通讯: 概念:两台设备之间通过网络实现数据传输;网络通讯:将数据通过网络从一台设备传输到另一台设备;java.net包下提供了一系列的类或接口,供…...
[代码随想录11]栈和队列的应用,逆波兰表达式求值 、滑动窗口最大值、前 K 个高频元素
前言 这几个题目都是栈和队列的高频面试题目,主要是考察思路和coding能力,在前面几道题目的基础上进行延伸的。同时还有优先级队列和双端队列的用法 题目链接 150. 逆波兰表达式求值 - 力扣(LeetCode) 239. 滑动窗口最大值 - 力…...
认证插件介绍
本文档是针对 UOS 登录器插件给出开发指南,目的是为了让开发人员了解如何在 UOS 登录器上增加一种自定义认证方式,对插件接口做了详细说明以及实战练习。 文章目录 一、认证插件可以做什么?二、认证流程三、术语说明四、安全性五、可靠性六、…...
ASP.NET Core8.0学习笔记(二十四)——EF Core级联插入与删除
一、EF Core导航关系操作——级联插入 1.级联插入:在含有导航属性的实体(主体实体)中可以对实体进行级联插入。即在创建主体实体时直接把依赖实体进行赋值,此时只需要执行一次插入操作即可将主体实体与依赖实体同时入库。同时&am…...
Docker打包SpringBoot项目
一、项目打成jar包 在进行docker打包之前,先确定一下,项目能够正常的打成JAR包,并且启动之后能够正常的访问。这一步看似是可有可无,但是能避免后期的一些无厘头问题。 二、Dockerfile 项目打包成功之后,需要编写Doc…...
【Linux】WSL:Win运行Linux
WSL2(Windows Subsystem for Linux 2) 是 Microsoft 开发的技术,可在 Windows 系统上运行完整的 Linux 发行版环境。以下是详细的配置教程。 安装与配置 启用 WSL 功能 打开“开始”菜单,搜索 PowerShell,以 管理员身…...
js循环导出多个word表格文档
文章目录 js循环导出多个word表格文档一、文档模板编辑二、安装依赖三、创建导出工具类exportWord.js四、调用五、效果图js循环导出多个word表格文档 结果案例: 一、文档模板编辑 二、安装依赖 // 实现word下载的主要依赖 npm install docxtemplater pizzip --save// 文件操…...
Spring Boot 日志 配置 SLF4J 和 Logback
前言 在开发 Java 应用时,日志记录是不可或缺的一部分。日志可以记录应用的运行状态、错误信息和调试信息,帮助开发者快速定位和解决问题。Spring Boot 项目默认集成了 SLF4J 和 Logback,使得日志配置变得简单而灵活。本文将详细介绍如何在 …...
企业级包管理器:专栏概述 (1)
在当今的前端开发领域,包管理器已经成为了每一位开发者不可或缺的工具。它们就像一个个神奇的工具箱,里面装满了各种各样的工具(即软件包),帮助我们快速搭建项目、实现功能,极大地提高了开发效率。接下来&a…...
【动手学电机驱动】STM32-MBD(1)安装 STM32 硬件支持包
STM32-MBD(1)安装 STM32 硬件支持包 【动手学电机驱动】STM32-MBD(1)安装 STM32 硬件支持包 1. 必须的软硬件条件2. 嵌入式硬件支持包2.1 Embedded Coder2.2 嵌入式硬件支持包2.3 Embedded Coder Support Package for STMicroelec…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...
2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...
376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...
SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题
分区配置 (ptab.json) img 属性介绍: img 属性指定分区存放的 image 名称,指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件,则以 proj_name:binary_name 格式指定文件名, proj_name 为工程 名&…...
Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...
免费PDF转图片工具
免费PDF转图片工具 一款简单易用的PDF转图片工具,可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件,也不需要在线上传文件,保护您的隐私。 工具截图 主要特点 🚀 快速转换:本地转换,无需等待上…...
uniapp 开发ios, xcode 提交app store connect 和 testflight内测
uniapp 中配置 配置manifest 文档:manifest.json 应用配置 | uni-app官网 hbuilderx中本地打包 下载IOS最新SDK 开发环境 | uni小程序SDK hbulderx 版本号:4.66 对应的sdk版本 4.66 两者必须一致 本地打包的资源导入到SDK 导入资源 | uni小程序SDK …...
从“安全密码”到测试体系:Gitee Test 赋能关键领域软件质量保障
关键领域软件测试的"安全密码":Gitee Test如何破解行业痛点 在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的"神经中枢"。从国防军工到能源电力,从金融交易到交通管控,这些关乎国计民生的关键领域…...
