從進程組、會話、終端的概念深入理解守護進程

来源:https://www.cnblogs.com/liwei0526vip/archive/2018/03/18/8589373.html
-Advertisement-
Play Games

寫在前面 「守護進程」是 Linux 的一種長期運行的後臺服務進程,也有人稱它為「精靈進程」。我們常見的 httpd、named、sshd 等服務都是以守護進程 Daemon 方式運行的,通常服務名稱以字母d結尾,也就是 Daemon 第一個字母。與普通進程相比它大概有如下特點: 無需控制終端(不需 ...


 

寫在前面

「守護進程」是 Linux 的一種長期運行的後臺服務進程,也有人稱它為「精靈進程」。我們常見的 httpd、named、sshd 等服務都是以守護進程 Daemon 方式運行的,通常服務名稱以字母d結尾,也就是 Daemon 第一個字母。與普通進程相比它大概有如下特點:

  • 無需控制終端(不需要與用戶交互)
  • 在後臺運行
  • 生命周期比較長,一般是隨系統啟動和關閉

守護進程必要性

為什麼要設置為守護進程,普通進程不可以嗎?

當我們在命令行提示符後輸入類似./helloworld程式時,在程式運行時終端被占用,此時無法執行其它操作。即使使用./helloworld &方式後臺運行,當連接終端的網路出現問題,那麼也會導致運行程式中斷。這些因素對於長期運行的服務來說很不友好,而「守護進程」可以很好的解決這個問題。

對進程組、會話、終端的理解

「守護進程」理解起來並不複雜,代碼編寫上有基本固定的套路。如果想要深入理解「守護進程」基本原理,那麼必須要首先理解 Linux 的進程、進程組、會話、終端等概念。

1、進程

  • 進程是 Linux 進行資源分配的最小單位
  • 前臺進程,例如這樣:$ ./hello
  • 後臺進程,例如這樣:$ ./hello & 釋放對控制終端的占用

2、進程組

每個進程都會屬於一個進程組,進程組中可以包含一個或多個進程。進程組中有一個進程組長,組長的進程 ID 是進程組 ID(PGID)

$ ps -o pid,pgid,ppid,comm | cat
PID PGID PPID COMMAND
10179 10179 10177 bash
10263 10263 10179 ps
10264 10263 10179 cat

下邊通過簡單的示例來理解進程組

  • bash:進程和進程組ID都是 10179,父進程其實是 sshd(10177)
  • ps:進程和進程組ID都是 10263,父進程是 bash(10179),因為是在 Shell 上執行的命令
  • cat:進程組 ID 與 ps 的進程組 ID 相同,父進程同樣是 bash(10179)

容易理解 Bash 就是Shell進程,Shell 父進程是 sshd;ps 與 cat 通過管道符號一起運行,屬於一個進程組,其父進程都是 Bash;一個進程組也被稱為「作業」。

3、會話(session)

多個進程組構成一個「會話」,建立會話的進程是會話的領導進程,該進程 ID 為會話的 SID。會話中的每個進程組稱為一個「作業」。會話可以有一個進程組稱為會話的「前臺作業」,其它進程組為「後臺作業」

一個會話可以有一個控制終端,當控制終端有輸入和輸出時都會傳遞給前臺進程組,比如Ctrl + Z。會話的意義在於能將多個作業通過一個終端控制,一個前臺操作,其它後臺運行。

4、前後臺作業相關操作

讓作業由進入後臺運行:

$ ping localhost >/dev/null &
[1] 10269 # 終端顯示
# [1]:作業ID 10269:進程組ID

給後臺作業發信號 SIGTERM

$ kill -SIGTERM -10269  # 發信號給進程組
$ kill -SIGTERM %1 # 發信號給作業1

讓後臺進程切換到前臺:

$ fg %1
# ping 進程重新切到前臺

編寫守護進程

編寫守護進程看似複雜,但實際上也是遵循一個特定的流程。

1、創建子進程,父進程退出

進程 fork 後,父進程退出。這麼做的原因有 2 點:

  • 如果守護進程是通過 Shell 啟動,父進程退出,Shell 就會認為任務執行完畢,這時子進程由 init 收養
  • 子進程繼承父進程的進程組 ID,保證了子進程不是進程組組長,因為後邊調用setsid()要求必須不是進程組長

2、子進程創建新會話

調用setsid()創建一個新的會話,併成為新會話組長。這個步驟主要是要與繼承父進程的會話、進程組、終端脫離關係。

3、禁止子進程重新打開終端

此刻子進程是會話組長,為了防止子進程重新打開終端,再次 fork 後退出父進程,也就是此子進程。這時子進程 2 不再是會話組長,無法再打開終端。其實這一步驟不是必須的,不過加上這一步驟會顯得更加嚴謹。

4、設置當前目錄為根目錄

如果守護進程的當前工作目錄是/usr/home目錄,那麼管理員在卸載/usr分區時會報錯的。為了避免這個問題,可以調用chdir()函數將工作目錄設置為根目錄/

5、設置文件許可權掩碼

文件許可權掩碼是指屏蔽掉文件許可權中的對應位。由於使用 fork()函數新建的子進程繼承了父進程的文件許可權掩碼,這就給該子進程使用文件帶來了諸多的麻煩。因此,把文件許可權掩碼設置為 0,可以大大增強該守護進程的靈活性。通常使用方法是umask(0)

6、關閉文件描述符

子進程會繼承已經打開的文件,它們占用系統資源,且可能導致所在文件系統無法卸載。此時守護進程與終端脫離,常說的輸入、輸出、錯誤描述符也應該關閉。

守護進程的出錯處理

由於守護進程脫離了終端,不能將錯誤信息輸出到控制終端,即使 gdb 也無法正常調試。常用的方法是使用 syslog 服務,將錯誤信息輸入到/var/log/messages中。

syslog 是 Linux 中的系統日誌管理服務,通過守護進程 syslogd 來維護。該守護進程在啟動時會讀一個配置文件/etc/syslog.conf。該文件決定了不同種類的消息會發送向何處。

守護進程編碼示例

pid_t pid, sid;
int i;
openlog("daemon_syslog", LOG_PID, LOG_DAEMON);
pid = fork(); // 第1步
if (pid < 0) exit(-1);
else if (pid > 0) exit(0); // 父進程第一次退出
if ((sid = setsid()) < 0) // 第2步
{
syslog(LOG_ERR, "%s\n", "setsid");
exit(-1);
}
// 第3步 第二次父進程退出
if ((pid = fork()) > 0) exit(0);
if ((sid = chdir("/")) < 0) // 第4步
{
syslog(LOG_ERR, "%s\n", "chdir");
exit(-1);
}
umask(0); // 第5步
// 第6步:關閉繼承的文件描述符
for(i = 0; i < getdtablesize(); i++)
{
close(i);
}
while(1)
{
do_something();
}
closelog();
exit(0);

到這裡基本上把守護進程的內容全部說清楚了,內容不少,概念比較晦澀,如果希望理解的比較透徹的話,可能需要多看幾遍了。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.1 需求問題的提出 五個與需求有關的敗因描述:(1)不完整的需求(2)缺乏用戶參與(3)不切實際的用戶期望(4)需求變更頻繁(5)提供了不再需要的需求 1.2 不同項目的需求視圖 不同的軟體項目具有不同的特點,這對需求也帶來了影響,在此主要從信息系統、嵌入式系統、軟體產品等不同角度說明如何進行相 ...
  • 無法在web伺服器上啟動調試,您沒有調試web伺服器進程的許可權,您需要以web伺服器的用戶賬戶身份運行,或者具有管理員許可權。 原因:從Windows NT 6.1開始,既Windows Vista版本開始,增強了用戶控制,尤其是Windows 8。如果沒有用系統優化軟體做過用戶控制,系統許可權調整,即 ...
  • 資料參考來源 : 我姓區不姓區 有關於WIF的介紹以及環境配置在此不多說,可以去網上搜索,或者點擊上方鏈接前往查看,以下所述都基於WIF配置完成的條件上; 以下很多東西都是從 我姓區不姓區 的博客直接copy過來的,我另外加的就是我跟著他的博客一路中所踩的坑以及我自己的理解; 開始單點登錄踩坑之旅: ...
  • 恢復內容開始 .net 項目開發管理中我們經常使用Nuget管理我們的類庫。由於某些原因 nuget v3的鏡像源https://api.nuget.org/v3/index.json 經常連接不上。 博客園提供了鏡像源 https://nuget.cnblogs.com/v3/index.json ...
  • 一門語言如果是另一個語言的超集的話,那麼這麼語言就要向後者相容,會變得臃腫,在某些方面的顯得過於複雜,如c++ 2.引用是可以獨立的存在的,當給一個引用進行初始化的時候,就是給這個引用添加了關聯 如 string a;和string a="as" 3.常量的使用通常都是放在程式的內部,但也可放在非r ...
  • 如上面的代碼,在方法前面添加 [Obsolete] 特性即可 2018.3.16 14:33 補充 使用這個重載形式,後面的布爾值表示是否在客戶調用該方法的時候報錯。這樣可以保證不會有人會誤用該方法 ...
  • 本文記錄了給字元串賦予字面值時,為便於操作與閱讀而進行的常用操作,如轉義序列,C#6的新功能‘字元串插入’以及一字不變的指定字元串等。 ...
  • .NET Core 是一個通用開發平臺,由 Microsoft 和 GitHub 上的 .NET 社區共同維護。 它是跨平臺的,支持 Windows、macOS 和 Linux,並且可用於設備、雲和嵌入式/IoT 方案。 本教程學習如何創建基於ASP.NET Core Razor頁面的Web應用程式... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...