基于tcp协议的网络通信(将服务端守护进程化)

news/2024/5/8 17:01:35/文章来源:https://blog.csdn.net/m0_74206992/article/details/136999449

目录

守护进程化

引入

介绍

如何实现 

思路

接口 -- setsid

注意点 

实现代码

daemon.hpp

log.hpp

运行情况


前情提要 -- 前后台任务介绍(区别+命令),session+sid介绍,session退出后的情况(nuhup,终端进程控制组),任务+进程组概念,任务与进程组的关系,-bash介绍-CSDN博客

守护进程化

引入

如果让他们可以不受这些的影响,这就是守护进程化

介绍

是一种使进程脱离终端会话控制,并在后台持续运行的技术

  • 守护进程通常是作为服务在系统中运行的后台进程,它们不会受到终端会话退出的影响,并且可以在系统启动时自动启动

如何实现 

思路

我们已经知道,启动的任务会自动属于当前的会话 -> 那么就会随着会话的退出而受到影响,且这个影响未知(有可能被终止,有可能还存在)

  • 如果我们想要让启动的任务不受到会话的影响,就可以让他自成一个会话
  • 也就是我们自己创建一个新会话,把它迁移过去
  • 这样,这个任务就不会受到原来那个会话的影响了,因为它已经归属其他会话了
  • (当然,这个新的会话不需要与键盘文件交互)

接口 -- setsid

创建一个会话,让当前进程脱离当前会话,成为新会话的进程组,并且让调用这个函数的进程的pgid作为sid

但他有一个条件,进程组的组长不能调用这个函数

  • 就相当于 -- 你在公司如果是个组长的职位,你告诉老板说自己想出去单干,老板肯定不愿意,他会说,你走不行,你下面的组员走可以
  • 所以,结合任务中第一个进程作为组长来看,我们可以考虑借助父子进程的特性来实现
  • 父进程会是组长,让他退出
  • 子进程作为组员,去执行守护进程化的工作
  • (毕竟父进程干等着也没啥用,工作是子进程的,唯一需要的就是释放子进程的资源,但这一工作可以让init进程干,也就是托孤给它)

注意点 

如果我们将服务端变成守护进程,那我们是不需要它在显示器上打印

  • 所以我们可以考虑将标准输出/错误关闭
  • 标准输入也不需要,因为后台任务本身就无法和键盘交互

但我们的服务端之前写过两种需要的打印:日志和debug语句

  • 如果直接关闭文件描述符,会导致写入错误
  • 所以,可以将他们重定向

如果需要日志的话,可以将它重定向到log.txt文件里

但dug语句确实不需要了,其中有两种做法:

  • 删除相关代码(但在代码量过大时,就不太方便了)
  • 将标准流重定向到/dev/null (它会将收到的数据直接丢弃,相当于垃圾桶)

当然,不要忘记处理SIGCHLD和SIGHUP这两个信号的处理方式

  • 因为我们的代码中可能会涉及到这两个信号:父子进程,终端退出等
  • 其他信号根据自己来设定,如果不希望这个服务端被暂停,也可以忽略SIGSTOP信号]

除此之外,守护进程也许需要修改自己的工作目录

  • 而且大部分的服务端都会修改自己的工作目录在根目录下,很可能还会将自己部署到系统中:
  • 总之,是有这个需求的
  • 所以,我们这里也提供支持
  • 也就是使用我们的chdir函数(之前在简单模拟shell中使用过 -- 模拟实现简易版shell(需要单独处理 ls+cd+export)_模拟实现一个简单的shell设计-CSDN博客):

 

实现代码

daemon.hpp

#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 null_path = "/dev/null";void daemon(const std::string &path = "")
{// 忽略信号signal(SIGCHLD, SIG_IGN);signal(SIGHUP, SIG_IGN);// 创建子进程if (fork() > 0){exit(0);}// 子进程成为守护进程setsid();// 修改工作目录if (!path.empty()){chdir(path.c_str());}// 重定向int fd = open(null_path.c_str(), O_RDWR);if (fd > 0){dup2(fd, 0);dup2(fd, 1);dup2(fd, 2);close(fd);}
}

log.hpp

#pragma once#include <iostream>
#include <time.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>#define INFO 0
#define DEBUG 1
#define WARNING 2
#define ERROR 3
#define FATAL 4 // 致命的错误#define SCREEN 1
#define ONEFILE 2#define DEF_NAME "log.txt"
#define DEF_PATH "./log/"#define SIZE 1024class Log
{
public:Log(): method_(SCREEN), path_(DEF_PATH){}void enable(){method_ = ONEFILE;}void operator()(int level, const char *format, ...){time_t t = time(nullptr);struct tm *ctime = localtime(&t);char leftbuffer[SIZE];snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%d-%d-%d %d:%d:%d]", levelToString(level).c_str(),ctime->tm_year + 1900, ctime->tm_mon + 1, ctime->tm_mday,ctime->tm_hour, ctime->tm_min, ctime->tm_sec);va_list s;va_start(s, format);char rightbuffer[SIZE];vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);va_end(s);// 格式:默认部分+自定义部分char logtxt[SIZE * 2];snprintf(logtxt, sizeof(logtxt), "%s %s", leftbuffer, rightbuffer);printLog(logtxt);}~Log(){}private:std::string levelToString(int level){switch (level){case INFO:return "INFO";case DEBUG:return "DEBUG";case WARNING:return "WARNING";case ERROR:return "ERROR";case FATAL:return "FATAL";default:return "NONE";}}void printLog(const std::string &logtxt){switch (method_){case SCREEN:std::cout << logtxt << std::endl;break;case ONEFILE:printOneFile(logtxt);break;default:break;}}void printOneFile(const std::string &info){std::string path = path_ + DEF_NAME;int fd = open(path.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666);//int fd = open("DEF_NAME", O_WRONLY | O_CREAT | O_APPEND, 0666);if (fd > 0){write(fd, info.c_str(), info.size());close(fd);}else{return;}}private:int method_;std::string path_;
};Log lg;

运行情况

服务端成功变成守护进程(孤儿进程+与终端无关+自成会话)

并且,随着客户端的登录/退出,log.txt也成功增加内容:

守护进程化的接口 -- daemon

参数

他有两个参数:

  • 如果想要把工作目录更换至根目录,nochdir=0;否则为当前路径
  • 如果想要将三个标准流重定向至/dev/null,noclose=0;否则不会对他们做处理

返回值 

​​​​​​​

  • 成功返回0
  • 失败返回-1,并设置错误码

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

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

相关文章

基于SSM框架的酒店预订系统

基于SSM框架的酒店预订系统的设计与实现 摘要 当今世界的互联网信息技术飞速发展&#xff0c;网络化的工作模式已经几乎覆盖到各个工作领域中的业务内&#xff0c;人们的日常生活也渐渐离不开互联网。因此&#xff0c;在当下全国各处的酒店都开始构建起了自己的网络预订系统。…

vue的优缺点有那些 组件常用的有那些?

优点&#xff1a; 组件化开发&#xff0c;提升效率&#xff0c;方便复用&#xff0c;便于协同开发单页面路由易于结合其他的第三方库丰富的api方法轻量高效,虚拟DOMMVVM&#xff0c;数据驱动视图轻量级的框架 缺点&#xff1a; 缺少高阶教程和文档生态环境不如angular和re…

【PHP + 代码审计】数组基础

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java、PHP】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收…

OpenHarmony系统服务的核心组件

简介 samgr组件是OpenHarmony的核心组件&#xff0c;提供OpenHarmony系统服务启动、注册、查询等功能。 系统架构 图 1 系统服务管理系统架构图 目录 /foundation/distributedschedule ├── samgr │ ├── bundle.json # 部件描述及编译文件 │ ├── frameworks…

Git的配置与简单的使用

Git概述 Git的工作流程 Git的配置与简单的使用 配置用户信息 配置用户名以及邮箱 邮箱尽量自己能够记住&#xff0c;以后会用到 git config --global user.name "Your name" git config --global user.email "Your email"查看用户信息 git config --…

警务数据仓库的实现

目录 一、SQL Server 2008 R2&#xff08;一&#xff09;SQL Server 的服务功能&#xff08;二&#xff09;SQL Server Management Studio&#xff08;三&#xff09;Microsoft Visual Studio 二、创建集成服务项目三、配置“旅馆_ETL”数据流任务四、配置“人员_ETL”数据流任…

ORA-29548

ORA-29548: Java system class reported: release of Java system classes in the database ( being determined) does not match that of the oracle executable (11.2.0.4.221018) 执行 java 报错 create or replace and compile java source named preg_replace aspackage…

深入解析MySQL的四种打开方式

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

嵌入式开发--STM32G431RBTx-定时器中断流水灯

嵌入式开发–STM32G431RBTx-定时器中断流水灯 定时器工作原理 如图有反映stm32g431的定时器资源。 共10个定时器 定时器定时器类型个数TIM6&#xff0c;7基本定时器2TIM2&#xff0c;3&#xff0c;4全功能通用定时器3TIM15&#xff0c;16&#xff0c;17通用定时器(只有1或2个…

51单片机中断信号的种类及应用场景

在嵌入式系统中&#xff0c;中断是一种重要的事件处理机制&#xff0c;它可以在程序执行的任何时候暂停当前任务&#xff0c;转而执行与之相关的特殊任务或事件。51单片机作为一种常见的微控制器&#xff0c;其中断功能在各种应用中起着关键作用。然而&#xff0c;对于初学者和…

权限提升-Win系统权限提升篇计算机管理用户进程注入令牌窃取服务启动远程控制

知识点 1、计算机管理用户到System-入口点和应用点 2、计算机管理用户到System-服务启动&远程控制 3、计算机管理用户到System-进程注入&令牌窃取 普通用户是没办法用(服务启动&远程控制、进程注入&令牌窃取等方法)提权到administrator、system权限的 而syst…

Git Commit 提交规范,变更日志、版本发布自动化和 Emoji 提交标准

前言 Git Commit 是开发的日常操作, 一个优秀的 Commit Message 不仅有助于他人 Review, 还可以有效的输出 CHANGELOG, 对项目的管理实际至关重要, 但是实际工作中却常常被大家忽略&#xff0c;希望通过本文&#xff0c;能够帮助大家规范 Git Commit&#xff0c;并且展示相关 …

Apache SeaTunnel和SeaTunnel Web 安装部署

Apache SeaTunnel和SeaTunnel Web 安装部署 前面我们介绍已经介绍过了Apache SeaTunnel,这里我们看一下SeaTunnel 的安装部署,早期的SeaTunnel 是没有web 页面的,只能在命令行里使用,现在SeaTunnel 已经有了web 端了,这就降低了我们的使用门槛 下载配置 我们可以去下面的…

【Word自动化办公】使用python-docx对Word进行操作

目录 一、环境安装 二、文档各组成结构获取 2.1 组成结构讲解 2.2 段落run对象的切分标准 三、获取整篇文档内容 四、写入指定样式的数据 4.1 通过add_paragraph与add_run参数添加样式 4.2 单独设置文本样式 五、添加标题 六、换行符&换页符 七、添加图片数据 …

Linux:rpm部署Jenkins(1)

1.获取Jenkins安装包 我这里使用的是centos7系统&#xff0c;ip为&#xff1a;192.168.6.6 2G运存 连接外网 Jenkins需要java环境&#xff0c;java的jdk包你可以去网上下载离线包&#xff0c;或者直接去yum安装&#xff0c;我这里使用的是yum安装 再去获取Jenkins的rpm包…

RabbitMQ的使用—实战

RabbitMQ的使用—实战 ​ RabbitMQ是一个开源的消息代理中间件&#xff0c;在分布式系统开发中被广泛应用。它实现了高级消息队列协议&#xff08;AMQP&#xff09;&#xff0c;提供可靠的消息传递、灵活的路由、消息确认等功能。下面是使用RabbitMQ的基本流程&#xff1a; 安…

(附源码)基于Spring Boot和Vue的前后端分离考研资料分享平台的设计与实现

前言 &#x1f497;博主介绍&#xff1a;✌专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f447;&#x1f3fb; 精彩专栏 推荐订阅&#x1f447;&#x1f3fb; 2024年Java精品实战案例《100套》 &#x1f345;文末获取源码联系&#x1f345; &#x1f31…

vue 消息左右滚动(前后无缝衔接)

之前一直用vue-seamless-scroll&#xff0c;无奈此组件有两个缺点不满足实际效果&#xff1a;1&#xff09;标题过长被截取、2&#xff09;标题果断也会滚动&#xff0c;无奈我自己封装一个&#xff0c;满足此两个弊端&#xff0c;也能达到vue-seamless-scroll组件的功能&#…

约数个数(数论,蓝桥杯)

题目描述&#xff1a; 给定一个数n&#xff0c;再给出n个数&#xff0c;现在要求你求出这些数的乘积的约数个数总和&#xff0c;结果对1e97取模。 取值范围&#xff1a;1<n<100; 1<ni<2e9; 分析步骤&#xff1a; 第一&#xff1a;要求约数的个数&#xff0c;我们有…

Canine IP-10/CXCL 10 ELISA试剂盒上新

科研用Canine IP-10/CXCL 10 ELISA试剂盒重磅来袭&#xff0c;将在免疫学、癌症研究与神经科学等多个领域助力各位老师们的研究&#xff01; 图1&#xff1a;犬IP-10/CXCL10结构预测&#xff08;图片来源&#xff1a;UniProt&#xff09; C-X-C基序趋化因子(C-X-C motif chemok…