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

news2024/11/15 18:03:02

目录

守护进程化

引入

介绍

如何实现 

思路

接口 -- 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 1024

class 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.coloradmin.cn/o/1545477.html

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

相关文章

深入了解服务器硬件:从基础知识到实际应用

在当今数字化的社会中&#xff0c;服务器扮演着至关重要的角色&#xff0c;它们是支撑互联网、云计算、大数据等技术发展的基石。而理解服务器硬件的基础知识对于从事IT领域的人员来说至关重要。本文将从服务器硬件的基础知识出发&#xff0c;介绍服务器硬件的组成、作用及其在…

Rust使用feature特性和条件编译,以及常用feature使用说明

Cargo Feature 是非常强大的机制&#xff0c;可以为大家提供条件编译和可选依赖的高级特性&#xff0c;可以为你省下不少的代码量来判断操作系统和条件编译等功能。rust官方条件编译文档&#xff1a;Conditional compilation - The Rust Reference features特性 Featuure 可以…

基于nodejs+vue电子产品销售系统设计与实现python-flask-django-php

该系统采用了nodejs技术、express框架&#xff0c;连接MySQL数据库&#xff0c;具有较高的信息传输速率与较强的数据处理能力。包含管理员和用户两个层级的用户角色&#xff0c;系统管理员可以对个人中心、用户管理、产品类别管理、电子产品管理、留言板管理、系统管理、订单管…

【开发篇】七、mybatis的foreach遍历,SQL拼接导致内存溢出

文章目录 1、背景2、快照文件分析3、本地环境复现4、结论5、解决方式 1、背景 文章微服务升级&#xff0c;新增了一个传入文章id的List&#xff0c;判断有多少id是存在的接口&#xff0c;第二天高峰期内存溢出。 2、快照文件分析 打开直方图&#xff0c;发现线程对象占用排第…

11.测试教程-自动化测试selenium-3

文章目录 1.unittest框架解析2.批量执行脚本2.1构建测试套件2.2用例的执行顺序2.3忽略用例执行 3.unittest断言4.HTML报告生成5.异常捕捉与错误截图6.数据驱动 大家好&#xff0c;我是晓星航。今天为大家带来的是 自动化测试selenium第三节 相关的讲解&#xff01;&#x1f600…

强!不用写一行代码!Python最强自动化神器!

1、Playwright介绍 Playwright是一个由Microsoft开发的开源自动化测试工具&#xff0c;它可以用于测试Web应用程序。Playwright支持多种浏览器&#xff0c;包括Chrome、Firefox和WebKit&#xff0c;同时也支持多种编程语言&#xff0c;如JavaScript、TypeScript、Python和C#。…

2014年认证杯SPSSPRO杯数学建模B题(第一阶段)位图的处理算法全过程文档及程序

2014年认证杯SPSSPRO杯数学建模 B题 位图的处理算法 原题再现&#xff1a; 图形&#xff08;或图像&#xff09;在计算机里主要有两种存储和表示方法。矢量图是使用点、直线或多边形等基于数学方程的几何对象来描述图形&#xff0c;位图则使用像素来描述图像。一般来说&#…

【Chrome控制台】application的使用

首先打开调试面板「windows:F12&#xff1b;mac&#xff1a;commandoptioni」&#xff0c;找到Application选项卡。 如下两区域与pwa相关&#xff0c;也就是渐进式web应用程序。 使用前端数据库如websql或IndexDB&#xff0c;可以在如下选项中查看。 数据库详情要到Storage中…

nysm:一款针对红队审计的隐蔽型后渗透安全测试容器

关于nysm nysm是一款针对红队审计的隐蔽型后渗透安全测试容器&#xff0c;该工具主要针对的是eBPF&#xff0c;能够帮助广大红队研究人员在后渗透测试场景下保持eBPF的隐蔽性。 功能特性 随着基于eBPF的安全工具越来越受社区欢迎&#xff0c;nysm也应运而生。该工具能保持各种…

Gitee码云最有价值开源项目之一:CRMEB开源商城系统,全平台、全功能的电商解决方案

一、引言 随着电子商务的快速发展&#xff0c;开源电商系统在行业中扮演着越来越重要的角色。CRMEB开源商城系统作为其中的佼佼者&#xff0c;凭借其强大的功能、卓越的性能和极高的易用性&#xff0c;成为了许多开发者和商家的首选。本文将对CRMEB开源商城系统进行深入的探讨…

Kimi是什么?免费Kimi chat介绍

1. Kimi是什么&#xff1f; Kimi是由月之暗面科技有限公司&#xff08;Moonshot AI&#xff09;开发的人工智能助手&#xff0c;专注于提供高质量的对话和信息处理服务。 月之暗面公司创立于2023年3月&#xff0c;创始团队核心成员参与了Google Gemini、Google Bard、盘古NLP、…

java算法第32天 | 贪心算法 part02 ● 122.买卖股票的最佳时机II ● 55. 跳跃游戏 ● 45.跳跃游戏II

122.买卖股票的最佳时机II 本题中理解利润拆分是关键点&#xff01; 不要整块的去看&#xff0c;而是把整体利润拆为每天的利润。假如第 0 天买入&#xff0c;第 3 天卖出&#xff0c;那么利润为&#xff1a;prices[3] - prices[0]。 相当于(prices[3] - prices[2]) (prices[…

迷宫(一)(DFS BFS)

//新生训练 #include <bits/stdc.h> using namespace std; int n, m; bool f; char mp[15][15]; int vis[15][15]; int dir[4][2] {{-1, 0}, {0, 1}, {1, 0}, {0, -1}}; bool in(int x, int y) {return 0 < x && x < n && 0 < y && y …

美人鱼图像双目配准-Mermaid

前言&#xff1a; 我在进行一项双目测距的项目&#xff0c;已经通过matlab 进行了相机标定&#xff0c;如果手动选择左右图像里的相同物体&#xff0c;是可以给出可接受距离的。 但是现在我希望能够让左视图的坐标点和右视图的坐标点进行匹配&#xff08;如下图&#xff09; …

Windows 安装 Java JDK 17 (源码方式安装)【图文详细教程】

这里我选择安装的 Java JDK 的版本为 17 Java JDK 下载 这里选择下载压缩包形式的 Java JDK&#xff0c;下载完成后&#xff0c;我们只需要对压缩包进行解压&#xff0c;然后再配置系统环境变量就可以了下载网址&#xff1a;https://www.oracle.com/cn/java/technologies/down…

【C语言】linux内核pci_enable_device函数和_PCI_NOP宏

pci_enable_device 一、注释 static int pci_enable_device_flags(struct pci_dev *dev, unsigned long flags) {struct pci_dev *bridge;int err;int i, bars 0;/** 此时电源状态可能是未知的&#xff0c;可能是由于新启动或者设备移除调用。* 因此获取当前的电源状态&…

电脑总是自动删除下载或解压后的文件

电脑总是自动删除下载或解压后的文件 前言&#xff1a; 最近navicat15 破解时候&#xff0c;下载安装包和破解包&#xff0c;破解包在解压后自动删除&#xff0c;要不然就是文件包含病毒电脑自动关闭打开功能。 解决方案&#xff1a; 注意&#xff1a;注意电脑重启或者重新打…

springboot 大文件分片上传

springboot 大文件分片上传 constantentityvocontrollerutils大文件分片上传是一种将大文件分割成多个小文件片段,然后分别上传这些小文件片段的方法。这种方法的好处包括: 减少重新上传开销:如果网络传输中断,只需重传未上传的部分,而不是整个文件。 提高灵活性:分片大小…

【ZZULI数据结构实验一】多项式的三则运算

【ZZULI数据结构实验一】多项式的四则运算 ♋ 结构设计♋ 方法声明♋ 方法实现&#x1f407; 定义一个多项式类型并初始化---CreateDataList&#x1f407; 增加节点---Getnewnode&#x1f407; 打印多项式类型的数据-- PrintPoly&#x1f407; 单链表的尾插--Listpush_back&…

Bert基础(七)--Bert实战之理解Bert模型结构

在篇我们将详细学习如何使用预训练的BERT模型。首先&#xff0c;我们将了解谷歌对外公开的预训练的BERT模型的不同配置。然后&#xff0c;我们将学习如何使用预训练的BERT模型作为特征提取器。此外&#xff0c;我们还将探究Hugging Face的Transformers库&#xff0c;学习如何使…