天天看點

建立 SysV 風格的 linux daemon 程式

本文介紹如何使用 C 語言建立 Linux 系統中 SysV 風格的 daemon 程式。注意:這是一種舊式的 daemon 程式寫法,進入 systemd 時代後是不需要通過這樣的方式建立 daemon 程式的。 本文的示範環境為 ubuntu 18.04。

通過前文《Linux session(會話)》我們了解到,如果要讓程式運作在背景,必須處理好程序的 session。是以在建立 daemon 程式的過程中處理 session 問題是很重要的一步,當然除此之外還需要其它的步驟。下面是在 Linux 系統中建立一個 SysV 風格的 daemon 的基本流程:

從父程序 fork 出一個子程序

為子程序建立新的 session ID

在子程序中再 fork 一次

修改 umask

修改程序的目前工作目錄

關閉程序中的檔案描述符

接下來我們通過代碼來介紹這些操作的含義。

建立一個子程序,如果成功就讓父程序退出,此時的子程序已經成為了 init 程序的子程序:

運作在背景的程序需要擺脫 session 終端的束縛,通過 setsid() 函數為程序設定新的 session ID 可以做到這一點:

********************************

執行到這裡時,PID==PGID==SID

建立 SysV 風格的 linux daemon 程式

這次 fork 的目的是防止程序再次獲得終端。因為隻有 session leader 才能獲得終端,而這次 fork 使子程序變成了非 session leader:

執行到這裡時,PGID==SID 但是已經不等于 PID 了,說明程序已經不是 session leader

建立 SysV 風格的 linux daemon 程式

為了能夠向 daemon 程序建立的任何檔案中寫入内容(包括日志),必須重置 umask(file mode mask, umask),以確定能夠正确地寫入或讀取這些檔案:

必須保證程序的目前工作目錄是存在的。因為衆多的 Linux 發行版中很多都沒有完全遵守标準的檔案目錄結構,是以最好是把程序的目前工作目錄設定為 /,這樣可以避免因設定了某個目錄而導緻它無法被 unmount:

關閉程序中所有打開的檔案描述符:

把日志寫入 syslog

Daemon 程式的日志非常重要,我們可以通過 openlog、syslog 和 closelog 三個函數把日志内容寫入到 syslog  中:

本文 demo 輸出的日志如下所示:

建立 SysV 風格的 linux daemon 程式

完整的代碼

把上面的代碼儲存到檔案 daemondemo.c 中(也可以從這裡下代碼),然後執行下面的指令進行編譯就可以得到可執行檔案 daemondemo:

這是一個很有意思的話題,有人說需要 fork 兩次,有人說第二次是可選的,究竟該如何做呢?當我們了解了第二次 fork 的用途後就可以自行決定是否需要第二次 fork 了。

這還需要從 session 的控制終端說起。控制終端是程序的一個屬性,通過 fork 系統調用建立的子程序會從父程序那裡繼承控制終端。這樣,session 中的所有程序都從 session 領頭程序那裡繼承控制終端。前面已經說過了,要把程式變成 daemon,就得讓程序擺脫 session 的終端。而這些在第一次 fork 後調用 setsid() 函數就搞定了。那麼如果接下來不小心再給程序添加了終端該怎麼辦?答案是不讓你添加!這就是第二次 fork 的作用。隻有 session leader 才能獲得終端,而第二次 fork 使子程序變成了非 session leader,你想犯錯也不給你機會了。

像 nginx 和 gblic 的 daemon 函數的實作都是 fork 一次,是以說第二次 fork 是可選的,你可以根據自己的實際情況來決定。

參考:

Linux Daemon Writing HOWTO

Creating a daemon in Linux

daemon man page

daemon 函數

Unix Daemon Server Programming

glibc daemon.c

作者:sparkdev

出處:http://www.cnblogs.com/sparkdev/

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。

繼續閱讀