🔥个人主页🔥:孤寂大仙V
🌈收录专栏🌈:linux
🌹往期回顾🌹: 【计算机网络】基于TCP进行socket编程——实现客户端到服务端远程命令行操作
🔖流水不争,争的是滔滔不息
一、进程组
进程组 = 一群可以一起接收信号的进程,它是 Linux 下进程管理的一个重要组织方式,尤其在 shell 控制、守护进程、kill 信号传递中非常有用。进程组是一个或者多个进程的集合,一个进程组可以包含多个进程。
写用一个管道写一个sleep的兄弟进程放到设置成后台任务,查看这个进程组的信息。这三个进程就属于一个进程组PGID相同。
组长进程
在上面图片中的PGID一列,发现sleep进程组的PGID等于第一个sleep进程的PID。每一个进程组都有一个组长进程,进程组id(PGID)=组长进程的id。
进程组组长的作用:进程组组长可以创建一个进程组或者创建该进程组中的进程。
进程组的生命周期是从进程组创建开始到其中最后一个进程离开。只有一个进程组中有一个进程存在,这个进程组就存在,与进程组的组长存不存在(是否终止)没关系。
进程组和任务的概念,任务就是某种工作,需要由进程来完成,进程组和任务可以理解为一个东西。
二、会话
**进程组是更小的单位。多个进程组组成一个会话(session)。**会话可以看作是多个进程组的集合。
在我们登录xshell的时候,完成登录认证,系统必须为用户新建一个会话,会话内部必须默认有一个进程组,叫做bash。在一个会话内,所有进程组的会话id(SID),都是这个进程组所处的会话的会话id。
通过键盘输入的数据,必须明确设置进程或者进程组。在会话内部,进程组必须区分为,前台进程和后台进程。 所以在一次会话中,有且只有一个前台进程组,后台进程可以有多个。一次会话中,有且只有一个前台任务,后台任务可以有多个。
当我们直接启动一个任务(进程组),这时这个任务是前台进程,就无法输入其他命令或进行其他操作了。因为这样直接启动的任务是前台进程。根据上面内容一个会话中只能有一个前台进程,接收命令的bash进程现在已经成后台进程了,没办法接收命令。把任务设置为后台执行,这是就可以执行其他命令与其他操作了。
作业控制
jobs查看系统当前的后台任务
fd+任务号,把指定的任务提到前台。
ctrl+c终止前台任务。
ctrl+z暂停进程或者进程组,且自动切换到后台。
bg+任务号,让后台进程运行起来。
守护进程
守护进程(Daemon Process)是指在后台运行、脱离终端控制、通常在系统启动时自动加载、长期运行的服务程序。
登录创建会话,关闭终端销毁会话,比如之前我们写的网络服务器,如果关闭终端了,会话就关了,会影响到服务器的运行。我们的服务器不能收到任何用户登录或者注销的影响。守护进程就是把这个进程组放到一个独立会话中,让任务成为独立会话内部的作业。
在 Linux 中,用户登录终端时会创建一个新的会话(Session),该会话中包含一个或多个进程组(Process Group)。一旦用户注销或关闭终端,该会话就会终止,所有隶属于该会话的前台和后台作业也会被系统自动终结。
对于如网络服务器这类应长期运行、稳定提供服务的程序,不能受到终端的控制或用户登录状态的影响。因此,我们需要将其转变为一个守护进程(Daemon),使其脱离控制终端、独立运行于自己的会话中。这样,即使用户退出登录,服务器进程仍能继续运行,稳定提供服务。
手写一个守护进程的接口
#pragma once#include <iostream>
#include <string>
#include <cstdio>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "Log.hpp"
#include "Common.hpp"using namespace LogModule;const std::string dev = "/dev/null";// 将服务进行守护进程化的服务
void Daemon(int nochdir, int noclose)
{// 1. 忽略IO,子进程退出等相关的信号signal(SIGPIPE, SIG_IGN);signal(SIGCHLD, SIG_IGN); // SIG_DFL// 2. 父进程直接结束if (fork() > 0)exit(0);// 3. 只能是子进程,孤儿了,父进程就是1setsid(); // 成为一个独立的会话if(nochdir == 0) // 更改进程的工作路径???为什么??chdir("/");// 4. 依旧可能显示器,键盘,stdin,stdout,stderr关联的.// 守护进程,不从键盘输入,也不需要向显示器打印// 方法1:关闭0,1,2 -- 不推荐// 方法2:打开/dev/null, 重定向标准输入,标准输出,标准错误到/dev/nullif (noclose == 0){int fd = ::open(dev.c_str(), O_RDWR);if (fd < 0){LOG(LogLevel::FATAL) << "open " << dev << " errno";exit(OPEN_ERR);}else{dup2(fd, 0);dup2(fd, 1);dup2(fd, 2);close(fd);}}
}
系统中自带的
daemon(1, 1);
把之前写的网络版本计算器,服务器端守护进程化。
源码