作者簡介
駱小剛,現就職於深圳市普康電子有限公司,高級軟件工程師。負責arm下u-boot、kernel開發,APP框架搭建,底層軟件開發,算法開發,性能優化等。對開源軟件有濃厚興趣。
本文主要用實例剖析systemd、daemon()、nohup啓動服務的差異。
環境:ubuntu 1804 x86_64, linux 5.0, gcc 8.3.0
1. systemd啓動服務
systemd是最新linux發行版管理後臺的服務的默認形式,用以取代原有的init。
1.1 編寫服務程序
vim simple-server.c
gcc simple-server.c -o simple-server
1.2 配置服務
編輯服務配置文件simple-server.service
vim simple-server.service
解析:
[Unit] :服務單元
Description:對該服務進行簡單的描述
[Service]:服務運行時行爲配置
ExecStart:程序的完整路徑
Restart:重啓配置,no、always、on-success、on-failure、on-abnormal、on-abort、on-watchdog
[Install]:安裝配置
WantedBy:多用戶等
其他配置選項請參考:
https://www.freedesktop.org/software/systemd/man/systemd.service.html
將配置拷貝到/lib/systemd/system/目錄下:
sudo cp simple-server.service /lib/systemd/system/
1.3 啓用服務
sudo systemctl enable simple-server
會創建一個指向配置文件/lib/systemd/system/simple-server.service的符號鏈接
/etc/systemd/system/multi-user.target.wants/simple-server.service
1.4 開啓服務
sudo systemctl start simple-server
1.5 服務狀態
1.5.1服務與終端的關係
pstree
可以看到systemd啓動的服務直接是pid=1的systemd進程的子進程。
可以看到服務程序忽略了SIGPIPE信號。
服務沒有控制終端(tty爲“?”)。
1.5.3 服務的運行日誌
sudo lsof -p 6213
用lsof可以看到服務的用戶爲root,當前目錄和根目錄都是“/”,輸入被重定向到/dev/null,輸出和出錯被重定向到socket。
1.5.4 服務的運行狀態
sudo systemctl status simple-server
我可以看到simple-server服務已經loaded,並且處於active狀態。還可以看到PID、Tasks數量、服務管理日誌等。
1.6 關閉服務
sudo systemctl stop simple-server
1.7 停用服務
sudo systemctl disable simple-server
2. daemon啓動服務
2.1 編寫代碼
vim daemon.c
gcc daemon.c -o daemon
2.2 啓動服務
./daemon
2.3 服務狀態
2.3.1 服務與終端的關係
服務把自己設置爲會話首領,父進程是當前用戶級的systemd(subreaper ),完全脫離終端。
2.3.2 服務的信號處理
ps -C daemon s
沒有屏蔽信號。
控制終端tty爲“?”
2.3.3 服務的運行日誌
當前目錄和根目錄都是“/”,用戶爲普通用戶,輸入、輸出、出錯都重定向到/dev/null
2.4 停止服務
killall daemon
3. nohup 啓動服務
3.1 編寫代碼
vim nohup.c
gcc nohup.c -o nohup
3.2 啓動服務
用nohup命令啓動這個名字也叫nohup的程序
(注意後面一個nohup是上面寫的那個很簡單的程序的名字)
nohup ./nohup
3.3 服務狀態
3.3.1服務與終端的關係
服務的父進程是啓動該服務的bash,和bash在一個會話組。
3.3.2 服務的信號處理
普通用戶,屏蔽SIGHUP信號,依賴終端bash。由於屏蔽了SIGHUP,終端關閉的時候,會忽略終端發送的SIGHUP信號,繼續運行服務。
3.3.3服務的運行日誌
輸入被重定向到/dev/null,輸出、出錯爲當前目錄下的nohup.out,格式沒有帶時間,不便於分析問題。
3.4 服務關閉
killall nohup
4. 總結
4.1 後臺運行服務的基本需求
基本需求:
脫離終端(終端關閉時,服務不能關閉)
處理輸入、輸出、出錯描述符
4.1.1 systemd
自己本身就是一個init或者user級的subreaper;
系統級systemd啓動的服務以root權限運行;
重定向輸入到/dev/null,輸出、出錯通過socket發給系統日誌模塊。
4.1.2 daemon
通過fork後父進程exit,讓子進程託孤給subreaper,實現在後臺運行服務。
重定向輸入、輸出、出錯到/dev/null.
源碼參考:
https://github.com/lattera/glibc/blob/master/misc/daemon.c
4.1.3 nohup
通過忽略終端關閉時的廣播信號SIGHUP,實現在後臺運行服務。
重定向輸入到/dev/null,輸出、出錯重定向到當前目錄下的nohup.out文件,
4.2 後臺運行服務的高級需求
高級需求:
方便分析問題的服務運行日誌記錄
服務管理的日誌
異常退出時可以根據需要重新啓動
daemon不能實現上面的高級需求。
nohup 只能記錄服務運行時的輸出和出錯日誌。
只有systemd能夠實現上述所有需求。
默認的日誌中增加了時間、用戶名、服務名稱、PID等,非常人性化。
還能看到服務運行異常退出的日誌。
還能通過/lib/systemd/system/下的配置文件定製各種需求。
還有非常非常多強大的功能等着你去探索:
https://www.freedesktop.org/software/systemd/man/systemd.html
4.3 systemd是目前linux管理後臺服務的主流方式
點一點右下角”在看”,爲閱碼場打Call~