特殊進程之守護進程

文章目錄

  • 1、守護進程的概念
  • 2、如何查看守護進程
  • 3、編寫守護進程的步驟
    • 3.1 創建子進程,父進程退出
    • 3.2 在子進程中創建新會話
    • 3.3 改變當前工作目錄
    • 3.4 重設文件權限掩碼
    • 3.5 關閉不需要的文件描述符
    • 3.6 某些特殊的守護進程打開/dev/null
  • 4、守護進程代碼示例

1、守護進程的概念

守護進程(Daemon Process),也就是通常說的 Daemon 進程(精靈進程),是 Linux 中的后臺服務進程。它是一個生存期較長的進程,通常獨立于控制終端并且周期性地執行某種任務或等待處理某些發生的事件。其他進程都是在用戶登錄或運行程序時創建,在運行結束或者用戶注銷時終止,但系統服務進程不受用戶登錄注銷的影響,它們一直運行,這就是守護進程。

守護進程是個特殊的孤兒進程,這種進程脫離終端,為什么要脫離終端呢?之所以脫離于終端是為了避免進程被任何終端所產生的信息所打斷,其在執行過程中的信息也不在任何終端上顯示。由于在 Linux 中,每一個系統與用戶進行交流的界面稱為終端,每一個從此終端開始運行的進程都會依附于這個終端,這個終端就稱為這些進程的控制終端,當控制終端被關閉時,相應的進程都會自動關閉。

Linux 的大多數服務器就是用守護進程實現的。比如,Internet 服務器 inetd,Web 服務器 httpd 等。

2、如何查看守護進程

在終端上使用命令 ps axj

a:表示顯示所有進程,包括其他用戶的進程。
x:不僅可以顯示有控制終端的進程,也可以顯示沒有控制終端的進程。
j:表示列出與作業控制相關的信息。

在這里插入圖片描述

上述字段含義如下:
PPID:父進程ID。

PID:當前進程ID。

PGID:當前進程的進程組ID。

SID:會話ID。

TTY:該進程在哪個終端下運作,其中“?”表示與終端機無關,例如守護進程;tty1-tty6是本機上的登錄者進程;pts/0等表示網絡連接進主機的進程。

TPGID:終端進程組ID。

STAT:進程狀態,其中“S”表示睡眠狀態,“R”表示運行狀態,“Z”表示僵尸狀態,“T”表示停止狀態,“W”表示等待狀態。

UID:用戶ID。

TIME:該進程使用的CPU時間。

COMMAND:正在運行的進程的命令名。

從上圖中可以看出守護進程都有以下特點:

守護進程基本上都是以超級用戶啟動( UID 為 0 )
沒有控制終端( TTY 為 ?)
終端進程組 ID 為 -1 ( TPGID 表示終端進程組 ID)

注意:COMMAND字段帶有[ ]的叫內核守護進程,不帶[ ]的叫普通守護進程,也叫做用戶守護進程。

一般情況下,守護進程可以通過以下方式啟動:

  1. 在系統啟動時由啟動腳本啟動,這些啟動腳本通常放在 /etc/rc.d 目錄下
  2. 利用 inetd 超級服務器啟動,如 telnet 等
  3. 由 cron 定時啟動以及在終端用 nohup 啟動的進程也是守護進程

這里面存放的基本都是守護進程的腳本
在這里插入圖片描述

在Linux中,守護進程有兩種方式,一種是svsy方式,一種是xinetd方式(超級守護進程)。 每個守護進程都會有一個腳本,可以理解成工作配置文件,守護進程的腳本需要放在指定位置,獨立啟動守護進程:放在/etc/rc.d 目錄下,當然也包括xinet的shell腳本;超級守護進程:按照xinet中腳本的指示,它所管理的守護進程位于/etc/xinetd.config目錄下。

sysv:

獨立啟動,一開機運行就會進入內存,一直處于listen狀態,即使該守護進程不運行也會一直占用系統資源,但是其最大的優點就是,它一直啟動,當有請求時會立即響應,響應速度快,比如http服務,這樣的進程都保存在/etc/rc.d/init.d目錄下

xinet d:

超級守護進程,管理眾多的進程,比如telnet服務。xinetd自己是一個sysv,它就像老板一樣,自己常駐于內存,管理其它的進程,其它進程就相當于它的員工,在其它進程沒有用時會睡眠,并不占用系統資源,當有工作時候老板xinetd會通知它的員工,喚醒某個進程來執行作業。這種方式適合于那些不是經常被人使用,不需要常駐內存的程序,但是此方式響應時間長,但是節省系統資源,方便管理。超級守護進程的配置文件是/etc/xinetd.conf,超級守護進程的子進程們存放在/etc/xinetd.d/目錄下

3、編寫守護進程的步驟

3.1 創建子進程,父進程退出

由于守護進程是脫離控制終端的,因此完成第一步后子進程變成后臺進程。之后的所有工作都在子進程中完成。而用戶通過 shell 可以執行其他的命令,從而在形式上做到了與控制終端的脫離。

雖然父進程退出了,但是子進程也不是進程組的組長進程,因為父進程退出,子進程成為孤兒進程,接著子進程會被init進程給領養,成為init 進程的子進程

父進程先退出,子進程就會成為孤兒進程
子進程退出,父進程沒有進行wait,子進程會成為僵尸進程

3.2 在子進程中創建新會話

這個步驟是創建守護進程中最重要的一步,在這里使用的函數是 setsid() 。

這里先要明確兩個概念:進程組和會話期。

進程組

進程組是一個或多個進程的集合。進程組由進程組 ID 來唯一標識。除了進程號( PID )之外,進程組 ID 也是一個進程的必備屬性。
每個進程組都有一個組長進程,其組長進程的進程號等于進程組 ID ,且進程組 ID 不會因組長進程的退出而受到影響。

會話期

會話期是一個或多個進程組的集合。通常一個會話開始于用戶登錄,終止于用戶退出;或者說開始于終端打開,結束于終端關閉。會話期的第一個進程稱為會話組長。在此期間該用戶運行的所有進程都屬于這個會話期。

進程組和會話期之間的關系如圖:

在這里插入圖片描述

setsid()函數說明
使用指令 man 2 setsid 查看詳細信息

#include <sys/types.h>
#include <unistd.h>pid_t setsid(void);

功能:
??如果調用進程不是進程組長,則 setsid() 將創建一個新會話。調用進程將成為新會話的會話組組長(即,其會話 ID 與其進程 ID 相同)。同時調用進程也將成為會話中新進程組的進程組組長(即,其進程組 ID 與其進程 ID 相同)。調用進程將是新進程組和新會話中的唯一進程。
參數:無
返回:
??成功:返回調用進程的(新)會話ID
??失敗:返回(pid_t)-1,并設置 errno

上面已經提到,setsid() 函數用于創建一個新的會話,并擔任該會話的組長,所以調用 setsid() 有下面 3 個作用

1、讓進程擺脫原會話的控制
2、讓進程擺脫原進程組的控制
3、讓進程擺脫原控制終端的控制

由于在調用 fork() 函數時,子進程 全盤復制 了父進程的會話期進程組和控制終端等。所以雖然父進程退出了,但原先的 會話期、進程組、控制終端等并沒有改變,因此,子進程并不是真正意義上的獨立,而 setsid() 函數能夠使進程完全獨立出來,從而脫離所有其他進程的控制。

3.3 改變當前工作目錄

使用 fork() 函數創建的子進程是完全繼承了父進程的當前工作目錄,所以從父進程繼承過來的當前工作目錄可能是一個掛載的文件系統中。因為守護進程有一般情況是在系統在引導之前是一直從在的,所以在進程工作的過程中當前目錄所在的文件系統(比如“/mnt/usb” 等)是不能卸載的。

因此,一般的做法是將根目錄作為守護進程的當前工作目錄,這樣就可以避免上述問題。當然,如有特殊需要,也可以把當前工作目錄換成其他的路徑,如“/tmp”。

改變工作目錄的函數是 chdir() 函數,其函數原型如下所示:

#include <unistd.h>int chdir(const char *path);

功能:
??改變調用者的工作目錄
參數:
??path:新的工作目錄的路徑
返回:
??成功:返回0
??失敗:返回-1,同時設置errno

3.4 重設文件權限掩碼

文件權限掩碼(通常用八進制表示)的作用是屏蔽文件權限中的對應位。例如,如果文件權限掩碼是0050,它表示屏蔽了文件所屬用戶組的可讀與可執行權限。由于使用 fork() 函數新建的子進程繼承了父進程的文件權限掩碼,這就給該子進程使用文件帶來了一定的影響。如果守護進程需要創建文件,那么他可能需要設置特定的權限。因此,把文件權限掩碼設置為一個已知的值(通常設置為0),可以增強該守護進程的靈活性。

umask的數值共有四位,例如上面的輸出0050,四位數表示四組權限值,分別是文件特殊權限,文件所有者權限,文件所屬用戶組權限,其他用戶權限。

這里我們先忽略掉文件特殊權限位。

可讀權限r表示4,可寫權限w表示2,可執行權限x表示1

umask值指的是需要從原始默認權限減掉的權限!我們已經知道r、w、x的數值分別是4、2、1。 所以如果要去掉可讀和可執行權限,umask值中相應的位就是5

如果要去掉讀權限,那就是4,去掉讀與寫權限,就是6,去掉執行與寫權限,就是3,去掉寫的權限,就是5!

新建文件和目錄的默認權限值就是在原始默認權限的基礎上去掉umask值,umask值與原始默認權限共同決定了新建文件和目錄的默認權限值。

在使用open()建立新文件時, 該參數mode 并非真正建立文件的權限, 而是 (mode&~umask)的權限值。

設置文件權限掩碼的函數是 umask()。在這里,通常的使用方法為 umask(0)。其函數原型如下所示:

#include <sys/types.h>
#include <sys/stat.h>mode_t umask(mode_t mask);

功能:
??umask() 將調用進程的文件模式創建掩碼(umask)設置為 mask & 0777(即僅使用掩碼的文件權限位)。
參數:
??mask:要設置的權限值,用八進制表示
返回:
??此系統調用始終成功,并返回掩碼的上一個值。

3.5 關閉不需要的文件描述符

同樣地,用 fork() 函數新建的子進程會從父進程那里繼承一些已經打開了的文件。這些被打開的文件可能永遠不會被守護進程訪問,但它們一樣占用系統資源,而且還可能導致所在的文件系統無法被卸載。

特別是守護進程和終端無關,所以指向終端設備的標準輸入、標準輸出和標準錯誤流等已經不再使用,應當被關閉。

可以使用函數 getdtablesize() 來獲取當前進程文件描述符表的大小,并通過使用 close() 來依次關閉。

函數原型如下:

#include <unistd.h>
int getdtablesize(void);

getdtablesize()函數返回進程可以打開的最大文件數,比文件描述符的最大可能值多一個。

#include <unistd.h>
int close(int fd);

close() 用于關閉文件描述符,關閉成功則返回 0,失敗則返回 -1 并設置 errno

所以關閉文件描述符的代碼可以如下寫法:

int num = getdtablesize(); // 獲取當前進程文件描述符表大小for (int i = 0; i < num; i++)  
{close (i);
}

3.6 某些特殊的守護進程打開/dev/null

某些特殊的守護進程打開/dev/null,使其具有文件描述符0、1、2,這樣任何一個試圖讀標準輸入、標準輸出、標準出錯時都不會有任何效果,這樣符合了守護進程不與終端設備相關聯的屬性。

/dev/null 是Linux下的黑洞文件,向里面寫入的所有數據都將被忽略

4、守護進程代碼示例

#include <stdio.h>     //for perror...
#include <string.h>    //for strlen...
#include <stdlib.h>    //for EXIT_FAILURE EXIT_SUCCESS...
#include <fcntl.h>     //for O_RDWR | O_CREAT | O_APPEND...
#include <unistd.h>    //for fork chidr setsid getdtablesize close...
#include <sys/types.h> //for umask...
#include <signal.h>    //for signal...volatile sig_atomic_t runing = 1;void sigint_handler(int sig)
{int fd = open("/tmp/dameon.log2", O_RDWR | O_CREAT | O_APPEND, 0644);char *p = "守護進程運行結束!\n";write(fd, p, strlen(p));close(fd);runing = 0;
}int main()
{// 創建子進程,父進程退出pid_t id = fork();if (id == -1){perror("fork");exit(EXIT_FAILURE);}if (id > 0) // 父進程{printf("父進程id:%d\n", getpid());exit(EXIT_SUCCESS);}//打印子進程號printf("子進程id:%d\n", getpid());// 在子進程中創建新會話pid_t temp_pid = setsid();// 改變當前的工作路徑chdir("/");// 改變進程本身的umaskumask(0);int num = getdtablesize(); /* 獲取當前進程文件描述符表大小 */int i = 0;for (i = 0; i < num; i++){close(i);}// 屏蔽一些控制終端操作的信號signal(SIGTTOU, SIG_IGN);signal(SIGTTIN, SIG_IGN);signal(SIGTSTP, SIG_IGN);signal(SIGHUP, SIG_IGN);// 對SIGINT進行捕獲signal(SIGINT, sigint_handler);while (runing){int fd = open("/tmp/dameon.log", O_RDWR | O_CREAT | O_APPEND, 0644);if (fd == -1){perror("open");exit(EXIT_FAILURE);}char *p = "這個一個守護進程!\n";write(fd, p, strlen(p));close(fd);sleep(3);}return 0;
}

編譯然后運行

在這里插入圖片描述

查看對應的日志文件

在這里插入圖片描述

向這個進程發送2號信號,進程則會捕獲到2號信號,觸發自定義函數,再次查看進程,發現進程已經結束

在這里插入圖片描述

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

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

相關文章

[UNILM]論文實現:Unified Language Model Pre-training for Natural Language.........

文章目錄 一、完整代碼二、論文解讀2.1 介紹2.2 架構2.3 輸入端2.4 結果 三、過程實現四、整體總結 論文&#xff1a;Unified Language Model Pre-training for Natural Language Understanding and Generation 作者&#xff1a;Li Dong, Nan Yang, Wenhui Wang, Furu Wei, Xia…

js new 原理

mdn new new 調用函數時&#xff0c;該函數將被用作構造函數 類只能用 new 運算符實例化 不使用 new 調用一個類將拋出 TypeError。 過程 new Foo(…) 執行時&#xff1a; 創建一個空的簡單 JavaScript 對象。 為方便起見&#xff0c;我們稱之為 newInstance。 如果構造函數…

華為OD機試真題-執行任務賺積分-2023年OD統一考試(C卷)

題目描述: 現有N個任務需要處理,同一時間只能處理一個任務,處理每個任務所需要的時間固定為1。 每個任務都有最晚處理時間限制和積分值,在最晚處理時間點之前處理完成任務才可獲得對應的積分獎勵。 可用于處理任務的時間有限,請問在有限的時間內,可獲得的最多積分。 輸入…

《LeetCode力扣練習》代碼隨想錄——字符串(替換數字---Java)

《LeetCode力扣練習》代碼隨想錄——字符串&#xff08;替換數字—Java&#xff09; 刷題思路來源于 代碼隨想錄 54. 替換數字 受制于語言限制&#xff0c;很普通的解法 import java.util.Scanner; class Main {public static void main(String[] args) {Scanner innew Scanner…

MyBatis--07--啟動過程分析、SqlSession安全問題、攔截器

提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 文章目錄 談談MyBatis的啟動過程具體的操作過程如下&#xff1a;實現測試類,并測試SqlSessionFactorySqlSession SqlSession有數據安全問題?在MyBatis中&#xff0c;SqlSess…

vuex如何存儲數據、獲取數據、以及數據的持久化

前提必須已經在vue中安裝了vuex插件不然無法使用&#xff0c;不知道怎么創建vue和安裝vuex的可以看這個視頻&#xff0c;node.js版本最好16以上不然可能會安裝失敗&#xff1a;30分鐘學會Vue之VueRouter&Vuex 趁著暑假掌握一門技能 大學生前端實習畢業設計必備技能_嗶哩嗶哩…

好代碼資源網整站打包代碼(包含了最新數據),集成了深度二開的ripro主題,非常適合做資源網站創業用

好代碼資源網是基于wordpress開發的一個資源分享類網站&#xff0c;在開發者圈子里還算小有名氣&#xff0c;這里分享嬰整站打包代碼&#xff08;包含了最新數據&#xff09;。網站本身集成了深度二開的ripro主題&#xff0c;非常適合做資源網站創業用。 資源下載類網站目前還…

Button背景顏色改不了,一直是默認的紫色

使用android.widget.Button <android.widget.Buttonandroid:layout_width"wrap_content"android:layout_height"wrap_content"android:onClick"doClick"android:text"這是一個按鈕"android:textColor"color/black"androi…

kubesphere安裝后啟用DevOps

官方文檔&#xff1a;KubeSphere DevOps 系統 1、集群管理---定制資源定義 進入目錄&#xff1a;集群管理---定制資源定義搜索&#xff1a;clusterconfiguration 點擊 ks-installer 右側的 &#xff0c;選擇編輯 YAML 在該 YAML 文件中&#xff0c;搜索 devops&#xff0c;…

力扣98. 驗證二叉搜索樹

深度優先遍歷 思路&#xff1a; 根據二叉搜索樹特性&#xff0c;通過中序遍歷得到有序序列&#xff0c;驗證序列是否有序來判斷&#xff1b;中序遍歷使用棧通過深度優先遍歷&#xff1b; /*** Definition for a binary tree node.* struct TreeNode {* int val;* Tre…

No CUDA GPUs are available

文章目錄 前言嘗試方法一、嘗試方法一二、嘗試方法二 總結 前言 之前用服務器跑的時候&#xff0c;發現是可以跑的。但當有其他人一同使用的時候&#xff0c;就會拋出&#xff1a;No CUDA GPUs are available&#xff0c;這個時候我嘗試了以下兩種方式解決&#xff0c;后面終于…

一到冬天,助聽器出現聲音小、無聲、時有時無……

冬天是一個寒冷干燥的季節&#xff0c;對于助聽器的使用者來說&#xff0c;也是一個需要特別注意保養的季節。助聽器是高精密的電子產品&#xff0c;如果不注意保養&#xff0c;可能會出現聲音小、無聲、時有時無等故障&#xff0c;影響聽力康復的效果。那么&#xff0c;冬天我…

C++中string類的使用

目錄 一.string類 1.1為什么學習string類&#xff1f; 1.2.標準庫中的string類 二.string對象的元素訪問 2.1.1使用operator[]與at實現訪問 2.1.2正向迭代器訪問 2.1.3反向迭代器訪問 2.1.4const正向迭代器&#xff08;不能修改&#xff09; 2.1.5const反向迭代器&#…

計算機網絡知識點合集【王道計算機考研】

學習的最大理由是想擺脫平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;遲一天就多一天平庸的困擾。各位小伙伴&#xff0c;如果您&#xff1a; 想系統/深入學習某技術知識點… 一個人摸索學習很難堅持&#xff0c;想組團高效學習… 想寫博客但無從下手&#xff0c;急需…

維護真實時間:應對系統時間篡改的技巧

引言 在App使用中&#xff0c;由于系統時間用戶可以隨意更改&#xff0c;在某些特殊情況下會導致獲取到的系統時間不正確問題。本篇代碼使用dart語言進行相關描述。 1.問題分析&#xff1a; 手機系統時間 ≠ 真實時間&#xff0c;當我們做一些需要對時間精度和準確性要求較高的…

SQL命令---修改數據庫的編碼

介紹 使用sql命令修改數據庫的編碼&#xff0c;修改為utf8mb4編碼。 命令 alter database 數據庫名稱 default character set utf8mb4;

垃圾收集算法和各種垃圾收集器的實現

深入理解Jvm虛擬機第三章 二、對象已死&#xff1f;3.2.1 引用計數算法3.2.2 可達性分析算法3.2.3 再談引用3.2.4 生存還是死亡3.2.5 回收方法區 三、垃圾收集算法3.3.1 分代收集理論3.3.2 標記-清除算法3.3.3 標記-復制算法3.3.4 標記-整理算法 四、HotSpot的算法細節實現3.4.…

單片機中的printf思考

問題: 1. printf自帶的庫編譯出來的大小比較大(flash吃緊) 2. printf是一個不定長參數, 意味著函數無法知道傳入的長度. 解決這個問題有2中方法:1.設置足夠大小的數組作為參數存儲; 2. 使用動態內存分配的方式來做(應該使用的是這個方式).(內存吃緊) 問題解釋: 1. 之前寫裸…

C# WPF上位機開發(串口界面設計)

【 聲明&#xff1a;版權所有&#xff0c;歡迎轉載&#xff0c;請勿用于商業用途。 聯系信箱&#xff1a;feixiaoxing 163.com】 如果只是把上位機看成是純軟件開發&#xff0c;本身不和硬件打交道的話&#xff0c;那么這就把上位機的操作范圍給限定死了。事實上&#xff0c;上…

多線程的使用

進程與線程 進程&#xff1a; 1、進程是指運行中的程序&#xff0c;比如我們使用QQ&#xff0c;就啟動了一個進程&#xff0c;操作系統就會為該進程分配內存空間。當我們使用微信&#xff0c;又啟動了一個進程,操作系統將為其分配新的內存空間。 2、進程是程序的一次執行過程…