1. 程式人生 > >在systemd下如何編寫我們的守護程序,利用systemd管理我們的守護程序

在systemd下如何編寫我們的守護程序,利用systemd管理我們的守護程序

     前言:在sysv init與upstart方式下,我們編寫守護程序的方法可參見我寫的其它文章,但思想與方法來源都是那本聖經《unix環境高階程式設計》,基本思路就是兩次fork,呼叫setsid()脫離終端(如果有的話),標準輸出入、標準輸出、標準出錯重定向等等;

     最近的一些linux distribution開始採用systemd作為sysv init和upstart的替代,如果我們想讓自己的程式(服務)被systemd管理,則編寫守護程序則要遵循一些systemd下的規則了....

一:systemd簡單介紹

http://www.ibm.com/developerworks/cn/linux/1407_liuming_init3/index.html

二:systemd下編寫守護程序遵循的幾點規則

開發人員需要了解 systemd 的更多細節。比如您打算開發一個新的系統服務,就必須瞭解如何讓這個服務能夠被 systemd 管理。這需要您注意以下這些要點:

  • 後臺服務程序程式碼不需要執行兩次派生來實現後臺精靈程序,只需要實現服務本身的主迴圈即可。(傳統編寫守護程序要至少呼叫一次fork,然後停止父程序)
  • 不要呼叫 setsid(),交給 systemd 處理
  • 不再需要維護 pid 檔案。(傳統編寫守護程序,會自己在某個目錄下,生成pid檔案,一是記錄本守護程序pid,另外一點是防止本守護程序被多次重啟而導致出錯或者導致多個例項在執行)
  • Systemd 提供了日誌功能,服務程序只需要輸出到 stderr 即可,無需使用 syslog。(傳統編寫守護程序我們要將標準輸出、出錯、輸入關閉或者重定向,日誌資訊都是發往rsyslog)
  • 處理訊號 SIGTERM,這個訊號的唯一正確作用就是停止當前服務,不要做其他的事情。(傳統守護程序一般SIGTERM也是用來做這種事情的)
  • SIGHUP 訊號的作用是重啟服務。(傳統資料程序一般SIGHUP也是做這種事情的)
  • 需要套接字的服務,不要自己建立套接字,讓 systemd 傳入套接字。(這個承接systemd快速啟動優點而設立的,可以實現這個特點,也可以不實現)
  • 使用 sd_notify()函式通知 systemd 服務自己的狀態改變。一般地,當服務初始化結束,進入服務就緒狀態時,可以呼叫它。(沒用過)

三:例項編寫

 1.python程式碼:

#! /usr/bin/python
import sys, os, socket, signal
serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
addr = '', 9090
serv.bind(addr)
serv.listen(5)

def sighup(num1, num2):
    sys.stderr.write("We receive SIGHUP signal...\nwe will reload the configuration file...\n")
def sigterm(num1, num2):
    sys.stderr.write("We kill us greacefully...\n")
    os._exit(0)

#handle signal SIGHUB
signal.signal(signal.SIGHUP, sighup)

#handler signal SIGTERM
signal.signal(signal.SIGTERM, sigterm)

sys.stderr.write("My self daemon start...\n")
while True:
    try:
        conn, addr = serv.accept()
    except Exception:
        continue
    try:
        pid = os.fork()
        if pid == 0:
           #child process close serv_socket_object of parent
           serv.close()
           time.sleep(5)
           os._exit(0)
        else:
           #parent process close conn_socket_object of child
           conn.close()
    except OSError:
        #if we use conn.close(), we must wait for python gc to 
        #really close the socket connection
        conn.shutdown(socket.SHUT_RDWR)

這就是一個普通的python程式,我們編寫了訊號處理函式,分別針對SIGHUB(用於重新讀取配置檔案)、SIGTERM(用於殺死自己)

    2.編寫service檔案

[[email protected] system]# pwd
/etc/systemd/system
[[email protected] system]# cat mydaemon.service 
[Unit]
Description=myDaemon 
[Service]
ExecStart=/root/mydaemon.py
ExecStop=/bin/kill -TERM $MAINPID
ExecReload=/bin/kill -HUP $MAINPID
killMode=process
After=network.target
[Install]
WantedBy=multi-user.target
我們在/etc/systemd/system新建mydaemon.service檔案,檔案內容如上

  3. 命令執行

接著我們執行:

[[email protected] system]# systemctl daemon-reload
再執行:
[[email protected] system]# systemctl start mydaemon

檢視一下狀態:
[[email protected] system]# systemctl status mydaemon
mydaemon.service - myDaemon
   Loaded: <span style="color:#ff0000;">loaded</span> (/etc/systemd/system/mydaemon.service; <span style="color:#ff0000;">disabled</span>)
   Active: <span style="color:#ff0000;">active</span> (running) since 三 2015-11-18 16:35:15 CST; 45min ago
 Main PID: 6873 (mydaemon.py)
   CGroup: /system.slice/mydaemon.service
           └─<span style="color:#ff0000;">6873 /usr/bin/python /root/mydaemon.py</span>

11月 18 16:35:15 localhost.localdomain systemd[1]: Started myDaemon.
11月 18 16:35:15 localhost.localdomain mydaemon.py[6873]: My self daemon start...
11月 18 16:35:36 localhost.localdomain systemd[1]: Reloading myDaemon.
11月 18 16:35:36 localhost.localdomain mydaemon.py[6873]: We receive SIGHUP signal...and we will reload the...ile
11月 18 16:35:36 localhost.localdomain systemd[1]: Reloaded myDaemon.
11月 18 17:19:00 localhost.localdomain systemd[1]: [/etc/systemd/system/mydaemon.service:7] Unknown lvalue...ice'
11月 18 17:19:00 localhost.localdomain systemd[1]: [/etc/systemd/system/mydaemon.service:8] Unknown lvalue...ice'
11月 18 17:20:12 localhost.localdomain systemd[1]: Started myDaemon.
Hint: Some lines were ellipsized, use -l to show in full.
正常啟動了,不過貌似我配置檔案寫的有點問題

現在我們驗證下systemd提供的日誌功能:

[[email protected] system]# systemctl reload mydaemon
日誌內容(命令內容:journalctl --unit mydaemon):
11月 18 17:20:12 localhost.localdomain systemd[1]: Started myDaemon.
11月 18 17:23:56 localhost.localdomain systemd[1]: Reloading myDaemon.
11月 18 17:23:56 localhost.localdomain mydaemon.py[6873]: <span style="color:#ff0000;">We receive SIGHUP signal...and we will reload the config</span>
11月 18 17:23:56 localhost.localdomain systemd[1]: Reloaded myDaemon.
紅色內容就是我們在程式中sys.stderr.write()的內容

當然,我們也可以設定為開機啟動,命令

[[email protected] system]# systemctl enable mydaemon

相關推薦

systemd如何編寫我們守護程序利用systemd管理我們守護程序

     前言:在sysv init與upstart方式下,我們編寫守護程序的方法可參見我寫的其它文章,但思想與方法來源都是那本聖經《unix環境高階程式設計》,基本思路就是兩次fork,呼叫setsid()脫離終端(如果有的話),標準輸出入、標準輸出、標準出錯重定向等等;

Android編寫一個登入介面利用資料庫實現記住密碼註冊賬號強制下線以及類似QQ的拉列表登入功能

        首先呢,看到這麼長的標題,是不是感覺這些功能有點難以實現呢,哈哈,其實並沒有想象中的那麼複雜,下面就跟著筆者來一起學習一下這些功能是怎麼實現的吧!         1.建立一個所有活動的父類,繼承自A

C#退出程序退出任務管理

nbsp brush system env environ 管理器 for 任務管理器 sin //窗體關閉之前 this.FormClosing += (s, r) => { System.Environment.Exit(0); }; //窗

[C#原始碼]網路資料流讀寫封裝類支援多執行緒同時讀和寫自動資源管理字串分隔符\r\n

using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using Syst

編寫一個程序將 d: java 目錄的所有.java 文件復制到d: jad 目錄並 將原來文件的擴展名從.java 改為.jad

clas targe 處理 ole AR 有意義 data stat exc 1.編寫一個程序,將 d: \ java 目錄下的所有.java 文件復制到d: \ jad 目錄下,並 將原來文件的擴展名從.java 改為.jad package copy; impo

梯有N階上樓可以一步上一階也可以一步上二階。編寫一個程序計算共有多少中不同的走法?

技術 告訴 不同的 mis misc 技術分享 blog main print c語言實現,小夥伴們誰要有更好的實現方法,要告訴我呦 #include int main(void) { int f,i,f1=1,f2=2; printf("請輸入樓梯數"); scanf(

linux用scp命令在兩個服務器之間傳輸文件利用php_scp函數進行文件傳輸

evc 在操作 path send 返回值 遠程 false cal 上傳 在linux下利用scp進行文件傳輸, 從服務器下載文件 scp [email protected]/* */:/path/filename /path/filename 上傳

通過編寫c語言程序運行時實現打印另一個程序的源代碼和行號

clas 行號 意義 spa clu 可執行 stdlib.h 讀取 進行 2017年6月1日程序編寫說明: 1.實現行號的打印,實現代碼的讀取和輸出,理解主函數中的參數含義。 2.對fgets函數理解不夠 3.對return(1); return 0的含義理解不夠 4.未

美工沒時間給圖簡單的圖讓我們自己寫哭啊! 所以具體研究了一下shape的使用保存

其它 結束 get alt 屬性 width drawable 樣式 ref 在drawable文件夾中創建一個shape的資源文件,其中shape有四個屬性(rectangle、oval、line、ring) 這四個屬性是用來定義圖形的形狀對應(矩形、橢圓、線、圓環) 除

編寫C#程序計算去除最大值和最小值之後的平均值

pub ole eric efault lis ner .get ast c# 有10位評委對跳水運動員做評分,編寫C#程序,計算去除最大得分和最小得分之後的平均得分 作為運動員的跳水成績。 interface IMark using System.Collections

解決archlinuxQT程序以及wineQQ無法輸入中文(.xinitrc)

light hup blog arc program xinitrc 無法 wineqq qt5 昨天安了i3wm,發現fcitx在很多程序中無法輸入中文,nixnote2,還有ss-qt5 查了wiki,明明有在~/.xinitrc中加入 export [email&#

自定義拉框樣式利用prototype制作

制作 pointer code javascrip .text att .com 自定義 cti <script type="text/javascript" src="js/jquery-1.7.2.min.js" ></script>

編寫程序試用公式計算圓面積和周長陳天藝1636050045

clas mat ext length double 計算 pub ble his public class Circle{private double r;public Circle(double r){this.r =r;}public double getLeng

項目版本不同導致Eclipse報錯問題——關於在JDK1.7環境中運行JDK1.8環境編寫的項目

water 錯誤 顯示 lips 1.8 ips avi 序號 fill 本人電腦環境配置的是JDK1.7,朋友的是JDK1.8 ,我把她編的java文件導入到我電腦裏的Eclipse(LUNA版本)的時候,項目出現一個紅色嘆號,當然運行是肯定出錯了。SO我就開始了解決之旅

作業: 1.8(圓的面積和周長)編寫程序使用以下的公式計算並顯示半徑為5.5的圓的面積和周長。

http string oid ren png ble -1 args 技術 public class Demo_1 { public static void main(String[] args) { double

【C語言程序】今天是祖國母親的生日特意編寫一個小程序為祖國母親慶生~

一個 img ges birt efi people print log blog #include <stdio.h>#define N 80 int main(int argc, char *argv[]) {char a[N];printf("Hello,

課程作業01 模仿JavaAppArguments.java示例編寫一個程序程序從命令行接收多個數字求和之後輸出結果。

技術 next highlight nbsp [] ++ pub 完成 一個 設計思想:主要是在命令行進行參數的轉化並相加輸出。由於命令行參數都是字符串,想要進行相加運算必須進行轉化,借助示例JavaAppArguments.java可以很好的進行轉化,之後再進行相加運算就

課程作業01:模仿JavaAppArguments.java示例編寫一個程序程序從命令行接收多個數字求和之後輸出結果。

解決問題 數據 代碼 spa clas blog 數字 循環求和 截圖 一、程序設計思想 解決問題的關鍵在於將參數進行數據類型的轉化,利用運行配置輸入的數據類型是String類型,故需要用Integer.parse()或者Integer.valueOf()將原有的Strin

模仿JavaAppArguments.java示例編寫一個程序程序從命令行接收多個數字求和之後輸出結果。

程序流程圖 註意 isp 流程 字符數 個數字 [] println nts [課程作業01] 設計思想 用args[]字符數組,用戶在參數表中依次輸入要相加的參數,程序統計用戶輸入的參數個數,依次輸出參數,sum賦初值為0,參數依次相加賦值給sum,最後輸出sum值。

編寫一個程序程序從命令行接收多個數字求和之後輸出結果。

編譯 技術 計算 求和 數字 定義 log int 結果 設計思想:定義int sum=0用於求和計算,在編譯器運行配置中輸入String類的數組,利用Integer.parseInt(arg);將數組轉化為int類進行相加,最後輸出結果。 程序流程圖: 源程序代碼:pu