0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Linux中如何編寫守護(hù)進(jìn)程程序

麥辣雞腿堡 ? 來(lái)源:嵌入式Linux系統(tǒng)開(kāi)發(fā) ? 作者:Jasonangel ? 2023-10-07 17:12 ? 次閱讀

守護(hù)進(jìn)程(Daemon)也稱為精靈進(jìn)程,是運(yùn)行在后臺(tái)的一種特殊進(jìn)程,它獨(dú)立于控制終端并且周期性地執(zhí)行某種任務(wù)或等待處理某些事情的發(fā)生,主要表現(xiàn)為以下兩個(gè)特點(diǎn):

? 長(zhǎng)期運(yùn)行。守護(hù)進(jìn)程是一種生存期很長(zhǎng)的一種進(jìn)程,它們一般在系統(tǒng)啟動(dòng)時(shí)開(kāi)始運(yùn)行,除非強(qiáng)行終止,否則直到系統(tǒng)關(guān)機(jī)都會(huì)保持運(yùn)行。與守護(hù)進(jìn)程相比,普通進(jìn)程都是在用戶登錄或運(yùn)行程序時(shí)創(chuàng)建,在運(yùn)行結(jié)束或用戶注銷時(shí)終止,但守護(hù)進(jìn)程不受用戶登錄注銷的影響,它們將會(huì)一直運(yùn)行著、直到系統(tǒng)關(guān)機(jī)。

? 與控制終端脫離。在 Linux 中,系統(tǒng)與用戶交互的界面稱為終端,每一個(gè)從終端開(kāi)始運(yùn)行的進(jìn)程都會(huì)依附于這個(gè)終端,這是上一小節(jié)給大家介紹的控制終端,也就是會(huì)話的控制終端。當(dāng)控制終端被關(guān)閉的時(shí)候,該會(huì)話就會(huì)退出,由控制終端運(yùn)行的所有進(jìn)程都會(huì)被終止,這使得普通進(jìn)程都是和運(yùn)行該進(jìn)程的終端相綁定的;但守護(hù)進(jìn)程能突破這種限制,它脫離終端并且在后臺(tái)運(yùn)行,脫離終端的目的是為了避免進(jìn)程在運(yùn)行的過(guò)程中的信息在終端顯示并且進(jìn)程也不會(huì)被任何終端所產(chǎn)生的信息所打斷。

守護(hù)進(jìn)程是一種很有用的進(jìn)程。Linux 中大多數(shù)服務(wù)器就是用守護(hù)進(jìn)程實(shí)現(xiàn)的,譬如,Internet 服務(wù)器 inetd、Web 服務(wù)器 httpd 等。同時(shí),守護(hù)進(jìn)程完成許多系統(tǒng)任務(wù),譬如作業(yè)規(guī)劃進(jìn)程 crond 等。

守護(hù)進(jìn)程 Daemon,通常簡(jiǎn)稱為 d,一般進(jìn)程名后面帶有 d 就表示它是一個(gè)守護(hù)進(jìn)程。守護(hù)進(jìn)程與終端無(wú)任何關(guān)聯(lián),用戶的登錄與注銷與守護(hù)進(jìn)程無(wú)關(guān)、不受其影響,守護(hù)進(jìn)程自成進(jìn)程組、自成會(huì)話,即pid=gid=sid。通過(guò)命令"ps -ajx"查看系統(tǒng)所有的進(jìn)程,如下所示:

圖片TTY 一欄是問(wèn)號(hào)?表示該進(jìn)程沒(méi)有控制終端,也就是守護(hù)進(jìn)程,其中 COMMAND 一欄使用中括號(hào)[]括起來(lái)的表示內(nèi)核線程,這些線程是在內(nèi)核里創(chuàng)建,沒(méi)有用戶空間代碼,因此沒(méi)有程序文件名和命令行,通常采用 k 開(kāi)頭的名字,表示 Kernel。

編寫守護(hù)進(jìn)程程序

  1. 創(chuàng)建子進(jìn)程、終止父進(jìn)程。父進(jìn)程調(diào)用 fork()創(chuàng)建子進(jìn)程,然后父進(jìn)程使用 exit()退出,這樣做實(shí)現(xiàn)了下面幾點(diǎn)。第一,如果該守護(hù)進(jìn)程是作為一條簡(jiǎn)單地 shell 命令啟動(dòng),那么父進(jìn)程終止會(huì)讓 shell 認(rèn)為這條命令已經(jīng)執(zhí)行完畢。第二,雖然子進(jìn)程繼承了父進(jìn)程的進(jìn)程組ID,但它有自己獨(dú)立的進(jìn)程ID,這保證了子進(jìn)程不是一個(gè)進(jìn)程組的組長(zhǎng)進(jìn)程,這是下面將要調(diào)用 setsid 函數(shù)的先決條件!
  2. 子進(jìn)程調(diào)用 setsid 創(chuàng)建會(huì)話。setsid()函數(shù)創(chuàng)建新的會(huì)話,由于之前子進(jìn)程并不是進(jìn)程組的組長(zhǎng)進(jìn)程,所以調(diào)用 setsid()會(huì)使得子進(jìn)程創(chuàng)建一個(gè)新的會(huì)話,子進(jìn)程成為新會(huì)話的首領(lǐng)進(jìn)程,同樣也創(chuàng)建了新的進(jìn)程組、子進(jìn)程成為組長(zhǎng)進(jìn)程,此時(shí)創(chuàng)建的會(huì)話將沒(méi)有控制終端。所以這里調(diào)用 setsid 有三個(gè)作用:讓子進(jìn)程擺脫原會(huì)話的控制、讓子進(jìn)程擺脫原進(jìn)程組的控制和讓子進(jìn)程擺脫原控制終端的控制。在調(diào)用 fork 函數(shù)時(shí),子進(jìn)程繼承了父進(jìn)程的會(huì)話、進(jìn)程組、控制終端等,雖然父進(jìn)程退出了,但原先的會(huì)話期、進(jìn)程組、控制終端等并沒(méi)有改變,因此,那還不是真正意義上使兩者獨(dú)立開(kāi)來(lái)。setsid 函數(shù)能夠使子進(jìn)程完全獨(dú)立出來(lái),從而脫離所有其他進(jìn)程的控制。
  3. 將工作目錄更改為根目錄。子進(jìn)程是繼承了父進(jìn)程的當(dāng)前工作目錄,由于在進(jìn)程運(yùn)行中,當(dāng)前目錄所在的文件系統(tǒng)是不能卸載的,這對(duì)以后使用會(huì)造成很多的麻煩。因此通常的做法是讓“/”作為守護(hù)進(jìn)程的當(dāng)前目錄,當(dāng)然也可以指定其 它目錄來(lái)作為守護(hù)進(jìn)程的工作目錄。
  4. 重設(shè)文件權(quán)限掩碼 umask。文件權(quán)限掩碼 umask 用于對(duì)新建文件的權(quán)限位進(jìn)行屏蔽,在 5.5.5 小節(jié)中有介紹。由于使用 fork 函數(shù)新建的子進(jìn)程繼承了父進(jìn)程的文件權(quán)限掩碼,這就給子進(jìn)程使用文件帶來(lái)了諸多的麻煩。因此,把文件權(quán)限掩 碼設(shè)置為 0,確保子進(jìn)程有最大操作權(quán)限、這樣可以大大增強(qiáng)該守護(hù)進(jìn)程的靈活性。設(shè)置文件權(quán)限掩碼的函數(shù)是 umask,通常的使用方法為 umask(0)。
  5. 關(guān)閉不再需要的文件描述符。子進(jìn)程繼承了父進(jìn)程的所有文件描述符,這些被打開(kāi)的文件可能永遠(yuǎn)不會(huì)被守護(hù)進(jìn)程(此時(shí)守護(hù)進(jìn)程指的就是子進(jìn)程,父進(jìn)程退出、子進(jìn)程成為守護(hù)進(jìn)程)讀或?qū)?,但它們一樣消耗系統(tǒng)資源,可能導(dǎo)致所在的文件系統(tǒng)無(wú)法卸載,所以必須關(guān)閉這些文件,這使得守護(hù)進(jìn)程不再持有從其父進(jìn)程繼承過(guò)來(lái)的任何文件描述符。
  6. 將文件描述符號(hào)為 0、1、2 定位到/dev/null。將守護(hù)進(jìn)程的標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出以及標(biāo)準(zhǔn)錯(cuò)誤重定向到/dev/null,這使得守護(hù)進(jìn)程的輸出無(wú)處顯示、也無(wú)處從交互式用戶那里接收輸入。
  7. 忽略 SIGCHLD 信號(hào)。處理 SIGCHLD 信號(hào)不是必須的,但對(duì)于某些進(jìn)程,特別是并發(fā)服務(wù)器進(jìn)程往往是特別重要的,服務(wù)器進(jìn)程在接收到客戶端請(qǐng)求時(shí)會(huì)創(chuàng)建子進(jìn)程去處理該請(qǐng)求,如果子進(jìn)程結(jié)束之后,父進(jìn)程沒(méi)有去 wait 回收子進(jìn)程,則子進(jìn)程將成為僵尸進(jìn)程;如果父進(jìn)程 wait 等待子進(jìn)程退出,將又會(huì)增加父進(jìn)程的負(fù)擔(dān)、也就是增加服務(wù)器的負(fù)擔(dān),影響服務(wù)器進(jìn)程的并發(fā)性能,在 Linux 下,可以將 SIGCHLD 信號(hào)的處理方式設(shè)置為SIG_IGN,也就是忽略該信號(hào),可讓內(nèi)核將僵尸進(jìn)程轉(zhuǎn)交給 init 進(jìn)程去處理,這樣既不會(huì)產(chǎn)生僵尸進(jìn)程、又省去了服務(wù)器進(jìn)程回收子進(jìn)程所占用的時(shí)間。
#include < stdio.h >
#include < stdlib.h >
#include < unistd.h >
#include < sys/types.h >
#include < sys/stat.h >
#include < fcntl.h >
#include < signal.h >
int main(void) {
   pid_t pid;
   int i;
   /* 創(chuàng)建子進(jìn)程 */
   pid = fork();
   if (0 > pid) {
     perror("fork error");
     exit(-1);
   }
   else if (0 < pid)//父進(jìn)程
     exit(0); //直接退出
   /*
   *子進(jìn)程
   */
   /* 1.創(chuàng)建新的會(huì)話、脫離控制終端 */
   if (0 > setsid()) {
   perror("setsid error");
   exit(-1);
   }
   /* 2.設(shè)置當(dāng)前工作目錄為根目錄 */
   if (0 > chdir("/")) {
     perror("chdir error");
     exit(-1);
   }
   /* 3.重設(shè)文件權(quán)限掩碼 umask */
   umask(0);
   /* 4.關(guān)閉所有文件描述符 */
   for (i = 0; i < sysconf(_SC_OPEN_MAX); i++)
     close(i);
   /* 5.將文件描述符號(hào)為 0、1、2 定位到/dev/null */
   open("/dev/null", O_RDWR);
   dup(0);
   dup(0);
   /* 6.忽略 SIGCHLD 信號(hào) */
   signal(SIGCHLD, SIG_IGN);
   /* 正式進(jìn)入到守護(hù)進(jìn)程 */
   for ( ; ; ) {
     sleep(1);
     puts("守護(hù)進(jìn)程運(yùn)行中......");
   }
   exit(0);
}

整個(gè)代碼的編寫都是根據(jù)上面的介紹來(lái)完成的。運(yùn)行之后,沒(méi)有任何打印信息輸出,原因在于守護(hù)進(jìn)程已經(jīng)脫離了控制終端,它的打印信息并不會(huì)輸出顯示到終端,在代碼中已經(jīng)將標(biāo)準(zhǔn)輸入、輸出以及錯(cuò)誤重定位到了/dev/null,/dev/null 是一個(gè)黑洞文件,自 然是看不到輸出信息。

守護(hù)進(jìn)程可以通過(guò)終端命令行啟動(dòng),但通常它們是由系統(tǒng)初始化腳本進(jìn)行啟動(dòng),譬如/etc/rc*或 /etc/init.d/*等。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11161

    瀏覽量

    208465
  • 終端
    +關(guān)注

    關(guān)注

    1

    文章

    1101

    瀏覽量

    29775
  • 程序
    +關(guān)注

    關(guān)注

    115

    文章

    3743

    瀏覽量

    80661
  • 系統(tǒng)
    +關(guān)注

    關(guān)注

    1

    文章

    1005

    瀏覽量

    21273
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Linux守護(hù)進(jìn)程

    1.守護(hù)進(jìn)程概述 守護(hù)進(jìn)程,也就是通常所說(shuō)的daemon進(jìn)程,是Linux
    發(fā)表于 08-22 09:17

    Linux進(jìn)程間通信方式-管道

    應(yīng)用程序開(kāi)發(fā)》熱點(diǎn)鏈接:1、Linux進(jìn)程間通信2、實(shí)驗(yàn):編寫守護(hù)進(jìn)程3、實(shí)驗(yàn):
    發(fā)表于 08-29 15:29

    實(shí)驗(yàn):編寫進(jìn)程程序

    1.實(shí)驗(yàn)?zāi)康?通過(guò)編寫進(jìn)程程序,使讀者熟練掌握f(shuō)ork()、exec()、wait()和waitpid()等函數(shù)的使用,進(jìn)一步理解在Linux
    發(fā)表于 09-05 15:32

    Linux學(xué)習(xí)雜談】之守護(hù)進(jìn)程以及簡(jiǎn)單創(chuàng)建

    首先我們需要了解一下什么叫做守護(hù)進(jìn)程,以及我們?yōu)槭裁葱枰@樣的進(jìn)程。我們知道當(dāng)我們寫一個(gè)簡(jiǎn)單的程序的時(shí)候我們知道,這個(gè)程序比如說(shuō)printf
    發(fā)表于 09-27 13:28

    初學(xué)者嵌入式linux系統(tǒng)的學(xué)習(xí)步驟

    /O 編寫串口通信程序 編寫多串口通信程序7、嵌入式系統(tǒng)進(jìn)程
    發(fā)表于 01-18 10:34

    Linux守護(hù)進(jìn)程詳解

    分享到:標(biāo)簽:進(jìn)程控制 Linux 守護(hù)進(jìn)程進(jìn)程 7.3 Linux
    發(fā)表于 10-18 14:24 ?0次下載
    <b class='flag-5'>Linux</b><b class='flag-5'>守護(hù)</b><b class='flag-5'>進(jìn)程</b>詳解

    進(jìn)程控制開(kāi)發(fā)之編寫進(jìn)程程序實(shí)驗(yàn)解析

    7.4.1 編寫進(jìn)程程序 1.實(shí)驗(yàn)?zāi)康?通過(guò)編寫進(jìn)程程序,使讀者熟練掌握f(shuō)ork()、exe
    發(fā)表于 10-18 16:33 ?0次下載
    <b class='flag-5'>進(jìn)程</b>控制開(kāi)發(fā)之<b class='flag-5'>編寫</b>多<b class='flag-5'>進(jìn)程</b><b class='flag-5'>程序</b>實(shí)驗(yàn)解析

    Linux系統(tǒng)網(wǎng)絡(luò)驅(qū)動(dòng)程序編寫

    驅(qū)動(dòng)程序編寫 一.Linux系統(tǒng)設(shè)備驅(qū)動(dòng)程序概述 1.1 Linux設(shè)備驅(qū)動(dòng)程序分類 1.2
    發(fā)表于 11-07 10:40 ?0次下載

    嵌入式linux系統(tǒng)的學(xué)習(xí)步驟

    串口通信 熟悉文件I/O 編寫串口通信程序 編寫多串口通信程序 7、嵌入式系統(tǒng)進(jìn)程
    發(fā)表于 07-23 13:59 ?952次閱讀

    你知道嵌入式linux系統(tǒng)下簡(jiǎn)單守護(hù)進(jìn)程(daemon)的編寫?

    嵌入式linux設(shè)備創(chuàng)建一個(gè)守護(hù)進(jìn)程,用于保護(hù)系統(tǒng)的主進(jìn)程,防止某些不可預(yù)期的意外導(dǎo)致主
    發(fā)表于 04-23 15:16 ?1380次閱讀
    你知道嵌入式<b class='flag-5'>linux</b>系統(tǒng)下簡(jiǎn)單<b class='flag-5'>守護(hù)</b><b class='flag-5'>進(jìn)程</b>(daemon)的<b class='flag-5'>編寫</b>?

    學(xué)會(huì)用日志了解你的 Linux 系統(tǒng)

    Linux 系統(tǒng)日志非常重要,后臺(tái)運(yùn)行的程序(通常被稱為守護(hù)進(jìn)程或者服務(wù)進(jìn)程)處理了你 Linux
    發(fā)表于 05-06 16:39 ?705次閱讀

    linux守護(hù)進(jìn)程實(shí)例

      今天完成一個(gè)守護(hù)進(jìn)程實(shí)驗(yàn)?! ? 熟悉守護(hù)進(jìn)程編寫和調(diào)試(系統(tǒng)日志)  2 編寫
    發(fā)表于 04-02 14:42 ?368次閱讀

    如何編寫基于ARM的裸機(jī)程序和基于Linux的驅(qū)動(dòng)程序

    在嵌入式開(kāi)發(fā),ADC應(yīng)用比較頻繁,本文主要講解ADC的基本原理以及如何編寫基于ARM的裸機(jī)程序和基于Linux的驅(qū)動(dòng)程序
    的頭像 發(fā)表于 09-13 09:25 ?3244次閱讀
    如何<b class='flag-5'>編寫</b>基于ARM的裸機(jī)<b class='flag-5'>程序</b>和基于<b class='flag-5'>Linux</b>的驅(qū)動(dòng)<b class='flag-5'>程序</b>

    Linux 安全模塊:守護(hù)進(jìn)程和套接字

    守護(hù)進(jìn)程通常是在后臺(tái)觀察操作以等待狀態(tài)、服務(wù)于特定子系統(tǒng)并確定整個(gè)系統(tǒng)的操作規(guī)則的實(shí)用程序。例如,一個(gè)守護(hù)進(jìn)程被配置為監(jiān)控打印服務(wù)的狀態(tài)。
    發(fā)表于 08-26 10:01 ?629次閱讀

    文盤Rust--把程序作為守護(hù)進(jìn)程啟動(dòng)

    當(dāng)我們寫完一個(gè)服務(wù)端程序,需要上線部署的時(shí)候,或多或少都會(huì)和操作系統(tǒng)的守護(hù)進(jìn)程打交道,畢竟誰(shuí)也不希望shell關(guān)閉既停服。今天我們就來(lái)聊聊這個(gè)事兒。
    的頭像 發(fā)表于 11-07 10:22 ?1008次閱讀