当前位置: 首页 > article >正文

linux网络套接字 | 深度解析守护进程 | 实现tcp服务守护进程化

        前言:本节主要内容是学习如何让一个服务编程守护进程一直运行在后台。 我们之前实现过tcp服务, 但是如果会话退出后这个服务就停止了。 很明显不符合需求。 所以我们就要学习本节内容学习——如何做到让一个服务编程守护进程!下面废话不多说, 开始我们的学习吧!

        ps:本节内容很简单, 友友们可以放心观看哦!

目录

前后台进程的概念

前后台操作

 什么是守护进程

如何做到守护进程


前后台进程的概念

        我们知道,当我们利用xshell登录远程主机之后, 我们就会默认有一个bash命令行输入命令。这其实是linux系统自动为我们生成了一个会话。bash就是这个会话里面的一个进程。 而且这个进程默认是打开的,在前台运行的。

        我们也知道,进程运行的时候, 再执行命令, 就没有什么用了。但是可以使用ctrl + C终止进程。

        为什么会有上面两种情况, 是因为我们在生成会话的时候, bash会被默认启动在前台, bash就可以为我们提供命令行服务。 这个时候bash和键盘相关,我们用户只需要拿着键盘向里面输入数据就行了。然后bash解释后, 就会去执行相应的命令。

        然后当我们启动一个进程, 这个时候就会由这个新的进程作为前台进程,bash进程就被挤掉了, 变成后台进程。 这个时候和键盘相关的是新进程, 我们再输入指令, 就是向新进程中输入指令, 新进程没有反应。 但是只对ctrl + c有反应。 

        然后上面两段话解释了两个结论, 也是事实:

  •         一个会话(session)里面,只有一个前台进程,多个后台任务。
  •         一个会话(session), 键盘信号只会发给前台进程。

        综上,为什么运行一个程序的时候ctrl + C可以终止,但是其他命令没有用呢,就是因为我们bash运行一个程序,然后bash就自动变成后台,然后运行的程序就变成前台了。这个时候再输入指令,就是输入给了前台进程, 也就是我们的程序!

        所以, 什么叫做前台:谁拥有标准输入(键盘)谁就是前台。

 

前后台操作

        可以在运行某个程序的指令后面加&, 表示后台运行某个程序。运行这个程序之后, 还会显示一个当前进程的后台任务号:

        接下来我们多创建几个后台任务:

 

        这个时候我们想要知道我们的会话中有哪些后台任务, 就可以使用jobs命令查看:

        上面是jobs查看后台进程, 我们可不可以让后台进程提到前台来呢? 答案是可以的,就是使用fg这个指令, fg + 后台任务号。就可以让后台进程提到前面来:

         然后我们再看。

        如果我们把某一个任务暂停了的时候, 这个时候bash进程就会默认被推到前台来。

        为什么会这样? 为什么默认是bash呢? 如果前台进程是一个我们自己写的进程, 我们暂停了这个进程,然后操作系统也不管, bash就继续呆在后台。那么这个时候整个会话里面就都是后台了,意味着没有进程能够在键盘里面获取输入。 这是不合理的, 所以我们就要让bash默认提到前台。

        同时, 如果让暂停的任务重新启动,那么他就会默认启动在后台。

 什么是守护进程

        我们要理解什么是守护进程, 就要先看一些铺垫。 我们先看这张图片:

        这张图片, process的pid是第二列。 然后PGID是进程组id, SID是session id。 TPGID以及后面的我们不管。 

        在这张图片中, 我们可以看到我们自己单独启动的process是自成一组, 另外一起创建的sleep是把多个进程之间的第一个进程的pid作为组id。 所以, 进程和进程之间也可以组成一个进程组。(进程组和任务的关系是什么? 任务在现实世界, 可能由一个人来完成, 也可以由一个团队来完成。 对应的就是一个任务由一个进程组来完成,这个进程组可能有一个人, 可能有多个人。

        每一个用户登录时都有一个session, 登陆时创建一个session, 退出时销毁一个session。 所以这么多session, 在操作系统层面上, 就要管理创建的session。 所以就要创建session结构体, 然后里面的sessionid就是表示哪一个session。 

        现在我们实验一个问题,就是我们一个会话如果启动了多个后台进程,当这个会话退出时,这些进程会不会退出。 我们现在创建两个会话, 一个会话用来创建进程,一个会话用来观察系统中还有没有后台进程。 一开始创建进程后:

        然后我们删除会话:

        我们就能看到, 会话会出, 连带着会话里面创建的进程也被退出了。说明这些进程受到了用户登录和推出的应i想, 如果不想受到用户登陆和注销的影响, 就要使用守护进程。 

        那么什么是守护进程?

         其实就是上面的一张图, 一开始有一个会话, 然后这个绘画里面有一个bash进程, 有其他的自己运行的进程。 这个时候我们如果让自己运行的进程自己形成一个会话。 那么我们原本的会话退出是否, 就影响不到我们创建的进程了。 这个就是守护进程!

如何做到守护进程

        如何让进程, 守护进程化。 这里就要用到一个函数, 叫做setsid。 创建一个新的会话设置新的进程组。

        这个创建的返回值就是会话的id, 也就是sid。 

        然后我们创建的新的会话一定不能是进程组的组长创建。 必须是组员创建新的会话:

        if(fork() > 0) exit(0);  //如果是父进程(父进程一定是一个进程组的组长), 那么就直接退出, 所有子进程同属于一个进程组。这些子进程都会变成守护进程。 

        守护进程的本质, 其实就是孤儿进程。 

        接下来开始编程, 我们想要让我们上一节实现的tcp服务守护进程化。 我们这里先创建一个文件,用来定义守护进程化的函数:

#pragma once

#include<iostream>
#include<cstdlib>
#include<unistd.h>
#include<signal.h>
#include<string>
using namespace std;

const string nullfile = "dev/null";

void Daemon(const string& cwd = "")
{
    //忽略其他信号
    signal(SIGCLD, SIG_IGN);
    signal(SIGPIPE, SIG_IGN);
    signal(SIGSTOP, SIG_IGN);

    //将自己变成独立的会话
    if (fork() > 0) exit(0);
    setsid();

    //更改当前调用进程的工作目录
    if (!cwd.empty())
    {
        chdir(cwd.c_str());
    }
    
    //将标准输出, 标准错误进行重定向到dev/null, 垃圾文件
    int fd = open(nullfile.c_str(), O_RDWR);

    if (fd > 0)
    {
        dup2(fd, 0);
        dup2(fd, 1);
        dup2(fd, 2);
        close(fd);
    }
    
}

        首先要确定的是if(fork() > 0) exit(0)这个语句, 这个语句就是为了让左右的进程进来, 然后出去的全部都是子进程。 然后就要让所有的进程守护进程化。 另外, 也要忽略其他信号。不要因为子进程而让自己退出了, 不要让自己写数据的时候直接退出了, 不要让进程被暂停了。  更改当前调用进程的工作目录。我们知道, 我们打开一个进程, 其实就是在当前目录下工作。 但是我们的守护进程是一个对外给别人提供服务的一个进程。想要将某些数据直接写到根目录, 所以这个时候就要更改守护进程的目录到根目录。 另外我们的守护进程也会打印一些日志信息, 这些日志信息我们可以通过日志小组件实现。 但是有些信息不是利用日志打印,而是直接cerr, cout。 那么这些信息可以放到一个垃圾文件里面, 也就是dev/null, 这是系统默认提供的垃圾文件。 用来回收垃圾信息的。

        然后我们在tcpserver里面调用这个函数, 启动的时候, 就能让tcp服务守护进程化:

        另外, 其实还有系统默认提供的守护进程函数:

        这个函数的第一个参数是nochdir, 意思就是说是否设置为零。设置为零,表示让当前进程工作在根目录下。否则就是用当前目录。 还有noclose, 如果设置就是将标准输入和标准错误重定向到dev/null。 这些功能我们上面都实现过。 这里不做赘述。 

 ——————以上就是本节全部内容哦, 如果对友友们有帮助的话可以关注博主, 方便学习更多知识哦!!!  


http://www.kler.cn/a/444889.html

相关文章:

  • Pytorch | 从零构建ResNet对CIFAR10进行分类
  • Spring Boot--06--整合Swagger
  • UE UMG 多级弹出菜单踩坑
  • qlib优缺点
  • C05S07-Tomcat服务架设
  • LeetCode刷题day29——动态规划(完全背包)
  • 联合目标检测与图像分类提升数据不平衡场景下的准确率
  • Linux创建普通用户和修改主机名
  • python tif处理 GDAL安装方法
  • Harmonyos多线程之Worker基本使用
  • 前端跨越方式有哪些
  • Jenkins 中 写 shell 命令执行失败,检测失败问题
  • Linux常用命令【真·常用】
  • DGCN论文解读
  • Python读取Excel批量写入到PPT生成词卡
  • 配置免密登陆服务器
  • python快速接入阿里云百炼大模型
  • 【数据分析】数据分析流程优化:从数据采集到可视化的全面指南
  • 一篇文章理解前端的请求头和响应头含义
  • 打 印 菱 形
  • Gartner发布2025年网络安全主要趋势:实现转型和嵌入弹性两大主题下的9个趋势
  • Linux性能监控命令_nmon 安装与使用以及生成分析Excel图表
  • 基于注意力机制的ResNet优化算法(三种注意力机制+源码+pytorch)
  • 4、交换机IP接口功能
  • git 删除鉴权缓存及账号信息
  • 基于时间情境创造与 AI 智能名片 S2B2C 商城小程序源码的零售创新策略研究