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服务守护进程化。 我们这里先创建一个文件,用来定义守护进程化的函数:

cpp 复制代码
#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。 这些功能我们上面都实现过。 这里不做赘述。

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

相关推荐
乙己4073 小时前
计算机网络——网络层
运维·服务器·计算机网络
飞行的俊哥3 小时前
Linux 内核学习 3b - 和copilot 讨论pci设备的物理地址在内核空间和用户空间映射到虚拟地址的区别
linux·驱动开发·copilot
幽兰的天空5 小时前
介绍 HTTP 请求如何实现跨域
网络·网络协议·http
lisenustc5 小时前
HTTP post请求工具类
网络·网络协议·http
心平气和️5 小时前
HTTP 配置与应用(不同网段)
网络·网络协议·计算机网络·http
心平气和️5 小时前
HTTP 配置与应用(局域网)
网络·计算机网络·http·智能路由器
hunter2062065 小时前
ubuntu向一个pc主机通过web发送数据,pc端通过工具直接查看收到的数据
linux·前端·ubuntu
Gworg6 小时前
网站HTTP改成HTTPS
网络协议·http·https
不会飞的小龙人6 小时前
Docker Compose创建镜像服务
linux·运维·docker·容器·镜像
不会飞的小龙人6 小时前
Docker基础安装与使用
linux·运维·docker·容器