如何將服務守護進程化

進程組


什么是進程組


之前我們提到了進程的概念, 其實每一個進程除了有一個進程 ID(PID)之外 還屬于一個進程組。進程組是一個或者多個進程的集合, 一個進程組可以包含多個進程。 每一個進程組也有一個唯一的進程組 ID(PGID), 并且這個 PGID 類似于進程 ID, 同樣是一個正整數, 可以存放在 pid_t 數據類型中。

C++
$ ps -eo pid,pgid,ppid,comm | grep test
#結果如下
PID  PGID  PPID  COMMAND
2830 2830  2259  test
# -e 選項表示 every 的意思, 表示輸出每一個進程信息
# -o 選項以逗號操作符(,)作為定界符, 可以指定要輸出的列

組長進程


每一個進程組都有一個組長進程。 組長進程的 ID 等于其進程 ID。我們可以通過 ps 命
令看到組長進程的現象:

Shell
[node@localhost code]$ ps -o pid,pgid,ppid,comm | cat
# 輸出結果
PID  PGID  PPID  COMMAND
2806 2806  2805   bash
2880 2880  2806    ps
2881 2880  2806   cat

從結果上看 ps 進程的 PID PGID 相同, 那也就是說明 ps 進程是該進程組的組長進程, 該進程組包括 ps 和 cat 兩個進程。進程組組長的作用: 進程組組長可以創建一個進程組或者創建該組中的進程進程組的生命周期: 從進程組創建開始到其中最后一個進程離開為止。注意:主要某個進程組中有一個進程存在, 則該進程組就存在, 這與其組長進程是否已經終止無關

會話


什么是會話


剛剛我們談到了進程組的概念, 那么會話又是什么呢? 會話其實和進程組息息相關,
會話可以看成是一個或多個進程組的集合, 一個會話可以包含多個進程組。每一個會
話也有一個會話 ID(SID)

通常我們都是使用管道將幾個進程編成一個進程組。 如上圖的進程組 2 和進程組 3 可
能是由下列命令形成的:

Shell
[node@localhost code]$ proc2 | proc3 &
[node@localhost code]$ proc4 | proc5 | proc6 &
# &表示將進程組放在后臺執行

我們舉一個例子觀察一下這個現象:

# 用管道和 sleep 組成一個進程組放在后臺運行
[node@localhost code]$ sleep 100 | sleep 200 | sleep 300 &
# 查看 ps 命令打出來的列描述信息
[node@localhost code]$ ps axj | head -n1

?

# 過濾 sleep 相關的進程信息
[node@localhost code]$ ps axj | grep sleep | grep -v grep
# a 選項表示不僅列當前?戶的進程,也列出所有其他?戶的進程
# x 選項表示不僅列有控制終端的進程,也列出所有?控制終端的進程
# j 選項表示列出與作業控制相關的信息, 作業控制后續會講
# grep 的-v 選項表示反向過濾, 即不過濾帶有 grep 字段相關的進程

從結果來看 3 個進程對應的 PGID 相同, 即屬于同一個進程組。

如何創建會話

可以調用 setseid 函數來創建一個會話, 前提是調用進程不能是一個進程組的組長。

#include <unistd.h>
/*
*功能:創建會話
*返回值:創建成功返回 SID, 失敗返回-1
*/
pid_t setsid(void);

該接口調用之后會發生:調用進程會變成新會話的會話首進程。此時, 新會話中只有唯一的一個進程,調用進程會變成進程組組長。 新進程組 ID 就是當前調用進程 ID,該進程沒有控制終端。 如果在調用 setsid 之前該進程存在控制終端, 則調用之后會切斷聯系

需要注意的是: 這個接口如果調用進程原來是進程組組長, 則會報錯, 為了避免這種情況, 我們通常的使用方法是先調用 fork 創建子進程, 父進程終止, 子進程繼續執行, 因為子進程會繼承父進程的進程組 ID, 而進程 ID 則是新分配的, 就不會出現錯誤的情況。

會話 ID(SID)


上邊我們提到了會話 ID, 那么會話 ID 是什么呢? 我們可以先說一下會話首進程, 會話首進程是具有唯一進程 ID 的單個進程, 那么我們可以將會話首進程的進程 ID 當做是會話 ID。注意:會話 ID 在有些地方也被稱為 會話首進程的進程組 ID, 因為會話首進程總是一個進程組的組長進程, 所以兩者是等價的。

控制終端


先說一下什么是控制終端?

在 UNIX 系統中,用戶通過終端登錄系統后得到一個 Shell 進程,這個終端成為 Shell進程的控制終端。控制終端是保存在 PCB 中的信息,我們知道 fork 進程會復制 PCB中的信息,因此由 Shell 進程啟動的其它進程的控制終端也是這個終端。默認情況下沒有重定向,每個進程的標準輸入、標準輸出和標準錯誤都指向控制終端,進程從標準輸入讀也就是讀用戶的鍵盤輸入,進程往標準輸出或標準錯誤輸出寫也就是輸出到顯示器上。另外會話、進程組以及控制終端還有一些其他的關系,我們在下邊詳細介紹一下:

一個會話可以有一個控制終端,通常會話首進程打開一個終端(終端設備或偽終端設備)后,該終端就成為該會話的控制終端。建立與控制終端連接的會話首進程被稱為控制進程。一個會話中的幾個進程組可被分成一個前臺進程組以及一個或者多個后臺進程組。如果一個會話有一個控制終端,則它有一個前臺進程組,會話中的其他進程組則為后臺進程組。無論何時進入終端的中斷鍵(ctrl+c)或退出鍵(ctrl+\),就會將中斷信號發送給前臺進程組的所有進程。如果終端接口檢測到調制解調器(或網絡)已經斷開,則將掛斷信號發送給控制進程(會話首進程)。

這些特性的關系如下圖所示:

守護進程

上篇博客寫了TCP,將服務器守護進程化

其余內容不變,只修改main.cc和引入封裝Daemon.hpp

Daemon.hpp

#pragma once
#include <iostream>
#include <cstdlib>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
const char *root = "/";
const char *dev_null = "/dev/null";
void Daemon(bool ischdir, bool isclose)
{// 1. 忽略可能引起程序異常退出的信號signal(SIGCHLD, SIG_IGN);signal(SIGPIPE, SIG_IGN);// 2. 讓自己不要成為組長if (fork() > 0)exit(0);// 3. 設置讓自己成為一個新的會話, 后面的代碼其實是子進程在走setsid();// 4. 每一個進程都有自己的 CWD,是否將當前進程的 CWD 更改成為 /根目錄if (ischdir)chdir(root);// 5. 已經變成守護進程啦,不需要和用戶的輸入輸出,錯誤進行關聯了if (isclose){close(0);close(1);close(2);}else{// 這里一般建議就用這種int fd = open(dev_null, O_RDWR);if (fd > 0){dup2(fd, 0);dup2(fd, 1);dup2(fd, 2);close(fd);}}
}

main.cc

#include"TcpServer.hpp"
#include <memory>
#include "Protocol.hpp"
#include"NetCal.hpp"
#include "Daemon.hpp"
void Usage(std::string proc)
{std::cerr<<"Usage: "<<proc<<"prot"<<std::endl;
}//  ./tcpserver 
int main(int argc,char* argv[])
{if(argc !=2){Usage(argv[0]);exit(USAGE_ERR);}Daemon(false, false);//1.頂層std::unique_ptr<Cal> cal = std::make_unique<Cal>();//2.協議層std::unique_ptr<Protocol> protocol = std::make_unique<Protocol>([&cal](Request &req)->Response{return cal->Execute(req);});//3.服務器層std::unique_ptr<TcpServer> tsvr = std::make_unique<TcpServer>(std::stoi(argv[1]),[&protocol](std::shared_ptr<Socket>&sock,InetAddr &client){protocol->GetReqquest(sock,client);});tsvr->Start();return 0;
}

此時將服務器放在后臺進程里鍵盤輸入的任何消息只會發送給前臺進程接收

?也可以調用系統調用

deamon

?

#include"TcpServer.hpp"
#include <memory>
#include "Protocol.hpp"
#include"NetCal.hpp"
#include "Daemon.hpp"#include <unistd.h>
void Usage(std::string proc)
{std::cerr<<"Usage: "<<proc<<"prot"<<std::endl;
}//  ./tcpserver 
int main(int argc,char* argv[])
{if(argc !=2){Usage(argv[0]);exit(USAGE_ERR);}daemon(0, 0);//1.頂層std::unique_ptr<Cal> cal = std::make_unique<Cal>();//2.協議層std::unique_ptr<Protocol> protocol = std::make_unique<Protocol>([&cal](Request &req)->Response{return cal->Execute(req);});//3.服務器層std::unique_ptr<TcpServer> tsvr = std::make_unique<TcpServer>(std::stoi(argv[1]),[&protocol](std::shared_ptr<Socket>&sock,InetAddr &client){protocol->GetReqquest(sock,client);});tsvr->Start();return 0;
}

效果也是一樣的

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/87936.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/87936.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/87936.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【跟著PMP學習項目管理】項目管理 之 范圍管理知識點

目錄 一、收集需求 1、知識點匯總 2、輸入 3、工具 4、輸出 二、定義范圍 1、知識點匯總 2、輸入 3、工具 4、輸出 三、創作工作分解結構 1、知識點匯總 2、輸入 3、工具 4、輸出 四、核實范圍 1、知識點匯總 2、輸入 3、工具 4、輸出 五、控制范圍 1、知…

AIX 環境磁盤空間管理指南

AIX 環境磁盤空間管理指南 在AIX環境中&#xff0c;磁盤空間的監控、管理與擴展是運維人員必備的技能。本文通過實際案例&#xff0c;系統地介紹如何查詢磁盤信息、卷組(VG)、邏輯卷(LV)信息&#xff0c;以及在磁盤空間不足時的擴容方案&#xff0c;幫助讀者掌握磁盤空間管理的…

k8s將service的IP對應的不同端口分配到不同的pod上

在Kubernetes中&#xff0c;Service是一種抽象層&#xff0c;它將請求路由到一組Pod。當你需要將Service的不同端口映射到不同的Pod時&#xff0c;可以通過以下兩種主要方式實現&#xff1a; 方法一&#xff1a;使用單個Service的多端口配置 如果不同的Pod提供不同的服務&…

aic8800M40低功耗sdio wifi在arm-linux平臺調試經驗

背景 好多年沒有搞過wifi相關的內容了,最近也被安排上了,把一顆低功耗aic8800M40的芯片在arm-linux開發板上做bring up,記錄一下SDIO wifi調試的過程和經驗,SDIO驅動這里需要改動一些linux內核HOST驅動代碼,會在文章中貼出來: AIC8800M40芯片簡介 這個wifi芯片是一顆低…

Redis基礎(1):NoSQL認識

SQL和NoSQL數據庫可以分為關系型數據庫和非關系型數據庫&#xff0c;SQL(Structured Query Language)相信大家并不陌生&#xff0c;這是用于操作關系型數據庫的語言&#xff0c;而NoSQL&#xff0c;顧名思義&#xff0c;它對應的就是非關系數據庫&#xff0c;它是操作非關系型數…

QT6 源(153)模型視圖架構里的表格窗體視圖 QTableWidget 篇三:源碼及其元素 QTableWidgetItem 的源代碼帶注釋

&#xff08;14&#xff09;本源代碼定義于頭文件 qtablewidget . h 頭文件 &#xff1a; #ifndef QTABLEWIDGET_H #define QTABLEWIDGET_H#include <QtWidgets/qtableview.h> #include <QtWidgets/qtwidgetsglobal.h> #include <QtCore/qlist.h> #include …

SSL證書是網絡安全的一把利刃

SSL證書&#xff08;安全套接層證書&#xff0c;現普遍升級為TLS證書&#xff09;確實是網絡安全領域中一把至關重要的“利刃”&#xff0c;它在保護數據傳輸安全、建立用戶信任、防范網絡攻擊等方面發揮著不可替代的作用。以下是其核心價值與作用的詳細分析&#xff1a;一、SS…

Apache 配置文件提權的實戰思考

在 Linux 系統中&#xff0c;如果普通用戶被授予以 sudo 執行 Apache 并加載自定義配置文件的權限&#xff08;如 sudo apache2 -f /home/user/user.conf&#xff09;&#xff0c;那么該權限極可能被濫用為本地提權路徑。 雖然 Apache 默認采用了更嚴格的權限限制機制&#xff…

代碼隨想錄算法訓練營第四十四天|動態規劃part11

1143.最長公共子序列 題目鏈接&#xff1a;1143. 最長公共子序列 - 力扣&#xff08;LeetCode&#xff09; 文章講解:代碼隨想錄 思路&#xff1a; 其實就是求兩個字符串的最長公共子序列的長度 與公共子數組的區別是可以不連續 &#xff0c;順序對就可以 狀態轉移方程不一樣 …

部署mysql

# 環境: 操作系統window11 安裝了vagrant 通過vagrant部署、啟動虛擬機(centos7) # 準備安裝mysql8 # 添加 MySQL 官方 YUM 源 sudo rpm -Uvh https://dev.mysql.com/get/mysql80-community-release-el7-7.noarch.rpm # 安裝 MySQL Server sudo yum install -y mysql-s…

SQL分析與打印-p6spy組件

有性能消耗&#xff0c;只推薦在非生產環境下使用 SpringBoot3MybatisPlushttps://baomidou.com/guides/p6spy/ MyBatis-Plus提供了SQL分析與打印的功能&#xff0c;通過集成p6spy組件&#xff0c;可以方便地輸出SQL語句及其執行時長。本功能適用于MyBatis-Plus 3.1.0及以上版本…

FLUX.1-Kontext 高效訓練 LoRA:釋放大語言模型定制化潛能的完整指南

在人工智能領域&#xff0c;尤其是大型語言模型&#xff08;LLM&#xff09;的應用浪潮中&#xff0c;高效、低成本地定制模型行為已成為關鍵需求。LoRA&#xff08;Low-Rank Adaptation&#xff09;技術以其參數高效、資源節省的特性脫穎而出。而 FLUX.1-Kontext 作為一款創新…

群暉 DS3617xs DSM 6.1.7 解決 PhotoStation 安裝失敗問題 PHP7.0

群暉 DS3617xs DSM 6.1.7 解決 PhotoStation 安裝失敗問題 PHP7.0問題描述解決方案1. 準備所需文件2. 檢查當前 PHP 版本3. 安裝 PHP 版本5. 查詢已安裝好的套件6. 升級 PHP 版本7. 手動安裝套件PhotoStation注意事項總結問題描述 在群暉 DS3617xs DSM 6.1.7-15284 版本中&…

pnpm 升級

pnpm 的安裝源太多了&#xff0c;感覺系統變量都有引入順序。 今天踩坑記錄&#xff1a; pnpm &#xff0c;如果最初用npm 裝的&#xff0c;可以用npm 升級&#xff1b; 如果最初用brew 裝的&#xff0c;得用brew 升級&#xff1b; 如果最初是用corepack 裝的得用corepack 升級…

[C#] WPF - 資源URI

一、組成 1、資源URI總共包括4個部分(當前程序集可以省略前3個)&#xff1a; ①&#xff1a;pack://application:,,, ②&#xff1a;/[程序集名稱] ③&#xff1a;;Component ④&#xff1a;/[資源路徑] 二、舉例 項目結構如下圖所示&#xff1a; 1、MainWindow.xaml 文件…

【Mysql系列】Mysql 多級隔離級別揭秘

目錄 一、什么是隔離級別 1.1、為什么復合操作需要事務&#xff1f; 1.2、事務的 ACID 特性如何保障操作可靠性&#xff1f; 1.3、隔離性通過隔離級別來控制 二、為什么用多級隔離級別 2.1、事務并發執行時可能引發以下問題 2.1.1、臟讀&#xff08;Dirty Read&#xff…

odoo17 警示: selection attribute will be ignored as the field is related

在 Odoo 17 中&#xff0c;當使用 related 字段時&#xff0c;直接在 fields.Selection 中指定選擇列表會被忽略&#xff08;因為選擇項會從關聯字段繼承&#xff09;。wtd_fuwlx fields.Selection(服務類型 , relatedwtd_id.fuwlx, storeTrue)遇到了一個警告&#xff0c;提示…

gemma-3n-E2B多模態模型使用案例:支持文本、圖像、語音輸入

參考&#xff1a; https://developers.googleblog.com/en/introducing-gemma-3n-developer-guide/下載&#xff1a; https://modelscope.cn/models/google/gemma-3n-E2B-it 模型下載 運行代碼&#xff1a; https://github.com/huggingface/huggingface-gemma-recipes 微調&…

計算機網絡實驗——互聯網安全實驗

實驗1. OSPF路由項欺騙攻擊和防御實驗一、實驗目的驗證路由器OSPF配置過程。驗證OSPF建立動態路由項過程。驗證OSPF路由項欺騙攻擊過程。驗證OSPF源端鑒別功能的配置過程。驗證OSPF防路由項欺騙攻擊功能的實現過程。二、實驗任務使用自己的語言簡述該實驗原理。如圖1所示的網絡…

Pytorch中torch.where()函數詳解和實戰示例

torch.where() 是 PyTorch 中非常常用的一個函數&#xff0c;功能類似于 NumPy 的 where&#xff0c;用于條件篩選或三元選擇操作。在深度學習訓練、掩碼操作、損失函數處理等場景中非常常見。一、基本語法 torch.where(condition, x, y)condition&#xff1a;一個布爾張量&…