最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

如何編寫python的daemon程序

 更新時間:2021年01月07日 10:51:17   作者:jhin  
這篇文章主要介紹了如何編寫python的daemon程序,幫助大家更好的理解和使用python,感興趣的朋友可以了解下

以前把守護進程與后臺任務搞混了,后面看了文章才知道這兩者的區(qū)別,寫此文表達自己對守護進程的理解.

1:什么是守護進程?

所謂守護進程是一種是 Linux 的一種長期運行的后臺服務進程,httpd、named、sshd 等服務都是以守護進程 Daemon 方式運行的,通常服務名稱以字母d結尾,也就是 Daemon 第一個字母.

  1. 無需控制終端(不需要與用戶交互)
  2. 在后臺運行
  3. 生命周期比較長,一般是隨系統(tǒng)啟動和關閉

2:守護進程必要性

通常我們執(zhí)行任務時是在前臺執(zhí)行,占領了當前終端,此時無法進行操作,就算我們添加了 &符號,將程序放到后臺,但也就因為終端斷網等問題,導致程序中斷。

所要知道的是:在目前的linux上,有了systemd這個服務,這個服務管理工具可以方便我們寫在后臺運行的程序,甚至可以代替這種守護進程。通過把寫服務的配置文件,讓systemd監(jiān)控我們的程序,可以隨系統(tǒng)啟動而運行,可以設定啟動條件,及其的方便。

3:進程組

$ ps -o pid,pgid,ppid,comm | cat
 PID PGID PPID COMMAND
10179 10179 10177 bash
10263 10263 10179 ps
10264 10263 10179 cat
  1. bash:進程和進程組ID都是 10179,父進程其實是 sshd(10177)
  2. ps:進程和進程組ID都是 10263,父進程是 bash(10179),因為是在 Shell 上執(zhí)行的命令
  3. cat:進程組 ID 與 ps 的進程組 ID 相同,父進程同樣是 bash(10179)

4:會話組

​ 多個進程構成一個進程組,而會話組是由多個進程組構建而。而進程組又被稱為job,會話有前臺作業(yè),也會有后臺作業(yè);一個會話可以有一個控制終端,當控制終端有輸入和輸出時都會傳遞給前臺進程組,比如Ctrl + Z。會話的意義在于能將多個作業(yè)通過一個終端控制,一個前臺操作,其它后臺運行。

那么如何編寫守護進程呢?

其實編寫守護進程很簡單,只需要遵循一下幾點即可

1:創(chuàng)建子進程,父進程退出

PPID  PID PGID  SID TTY   TPGID STAT  UID  TIME COMMAND
  0  49  49  49 pts/2    70 Ss    0  0:00 /bin/bash
  49  70  70  49 pts/2    70 R+    0  0:00 \_ ps axjf
  0  17  17  17 pts/1    68 Ss    0  0:00 /bin/bash
  17  68  68  17 pts/1    68 S+    0  0:00 \_ python hello.py
  68  69  68  17 pts/1    68 S+    0  0:00   \_ python hello.py
  0   1   1   1 pts/0    1 Ss+   0  0:00 /bin/bash

進程 fork 后,父進程退出。這么做的原因有 2 點:

如果守護進程是通過 Shell 啟動,父進程退出,Shell 就會認為任務執(zhí)行完畢,這時子進程由 init 收養(yǎng)
子進程繼承父進程的進程組 ID,保證了子進程不是進程組組長,因為后邊調用setsid()要求必須不是進程組長
PGID就是進程所屬的Group的Leader的PID,如果PGID=PID,那么該進程是Group Leader

2、子進程創(chuàng)建新會話

調用setsid()創(chuàng)建一個新的會話,并成為新會話組長。這個步驟主要是要與繼承父進程的會話、進程組、終端脫離關系。

那么問題來了,為什么進程組組長無法調用setsid()呢?

對于進程組長來說,進程組 ID 已經和 PID 相同了,如果它被允許調用setsid()的話,它的進程組 ID 會保持不變,會出現:

1:進程組長屬于新的會話;

2:老的進程組成員屬于舊的會話。

這樣情況變成了一個進程組的成員屬于不同的會話,Linux想要禁止這種情況的發(fā)生。

3、禁止子進程重新打開終端

此刻子進程是會話組長,為了防止子進程重新打開終端,再次 fork 后退出父進程,也就是此子進程。這時子進程 2 不再是會話組長,無法再打開終端。其實這一步驟不是必須的,不過加上這一步驟會顯得更加嚴謹。

4、設置當前目錄為根目錄

如果守護進程的當前工作目錄是/usr/home目錄,那么管理員在卸載/usr分區(qū)時會報錯的。為了避免這個問題,可以調用chdir()函數將工作目錄設置為根目錄/。

5、設置文件權限掩碼

文件權限掩碼是指屏蔽掉文件權限中的對應位。由于使用 fork()函數新建的子進程繼承了父進程的文件權限掩碼,這就給該子進程使用文件帶來了諸多的麻煩。因此,把文件權限掩碼設置為 0,可以大大增強該守護進程的靈活性。通常使用方法是umask(0)。

6、關閉文件描述符

子進程會繼承已經打開的文件,它們占用系統(tǒng)資源,且可能導致所在文件系統(tǒng)無法卸載。此時守護進程與終端脫離,常說的輸入、輸出、錯誤描述符也應該關閉,畢竟這個時候也不會使用終端了。

守護進程的出錯處理

由于守護進程脫離了終端,不能將錯誤信息輸出到控制終端,即使 gdb 也無法正常調試。常用的方法是使用 syslog 服務,將錯誤信息輸入到/var/log/messages中。

syslog 是 Linux 中的系統(tǒng)日志管理服務,通過守護進程 syslogd 來維護。該守護進程在啟動時會讀一個配置文件/etc/syslog.conf。該文件決定了不同種類的消息會發(fā)送向何處。

代碼展示

import os
import sys


def daemonize(pid_file=None):
  pid = os.fork()
  if pid:
    sys.exit(0)
  os.setsid()

  _pid = os.fork()
  if _pid:
    sys.exit(0)

  os.umask(0)
  os.chdir('/')
  sys.stdout.flush()
  sys.stderr.flush()

  with open('/dev/null') as read_null, open('/dev/null','w') as write_null:
    os.dup2(read_null.fileno(), sys.stdin.fileno())
    os.dup2(write_null.fileno(), sys.stdout.fileno())
    os.dup2(write_null.fileno(), sys.stderr.fileno())

  if pid_file:
    with open(pid_file,'w+') as f:
      f.write(str(os.getpid()))

if __name__ == "__main__":
  daemonize('test.txt')

關于os.dup2這個函數

os.dup2() 方法用于將一個文件描述符 fd 復制到另一個 fd2。
Unix, Windows 上可用。

>>> import os
>>> f = open("hello.txt","a")
>>> os.dup2(f.fileno(),1)
>>> f.close()
>>> print("hello world")
>>> print("changed")
cat hello.txt
1
hello world
changed

附加話題

為什么服務器端常常fork兩次呢?

因為這是為了避免產生僵尸進程。

當我們只fork()一次后,存在父進程和子進程。這時有兩種方法來避免產生僵尸進程:

  • 父進程調用waitpid()等函數來接收子進程退出狀態(tài)。
  • 父進程先結束,子進程則自動托管到Init進程(pid = 1)。

目前先考慮子進程先于父進程結束的情況:

  • 若父進程未處理子進程退出狀態(tài),在父進程退出前,子進程一直處于僵尸進程狀態(tài)。
  • 若父進程調用waitpid()(這里使用阻塞調用確保子進程先于父進程結束)來等待子進程結束,將會使父進程在調用waitpid()后進入睡眠狀態(tài),只有子進程結束父進程的waitpid()才會返回。 如果存在子進程結束,但父進程還未執(zhí)行到waitpid()的情況,那么這段時期子進程也將處于僵尸進程狀態(tài)。

由此,可以看出父進程與子進程有父子關系,除非保證父進程先于子進程結束或者保證父進程在子進程結束前執(zhí)行waitpid(),子進程均有機會成為僵尸進程。那么如何使父進程更方便地創(chuàng)建不會成為僵尸進程的子進程呢?這就要用兩次fork()了。

父進程一次fork()后產生一個子進程隨后立即執(zhí)行waitpid(子進程pid, NULL, 0)來等待子進程結束,然后子進程fork()后產生孫子進程隨后立即exit(0)。這樣子進程順利終止(父進程僅僅給子進程收尸,并不需要子進程的返回值),然后父進程繼續(xù)執(zhí)行。這時的孫子進程由于失去了它的父進程(即是父進程的子進程),將被轉交給Init進程托管。于是父進程與孫子進程無繼承關系了,它們的父進程均為Init,Init進程在其子進程結束時會自動收尸,這樣也就不會產生僵尸進程了。

以上就是如何編寫python的daemon程序的詳細內容,更多關于python的daemon程序的資料請關注腳本之家其它相關文章!

相關文章

  • Python列表(list)常用操作方法小結

    Python列表(list)常用操作方法小結

    這篇文章主要介紹了Python列表(list)常用操作方法小結,本文講解了常用操作方法和一些簡單代碼實例,需要的朋友可以參考下
    2015-02-02
  • Python編程基礎之輸入與輸出

    Python編程基礎之輸入與輸出

    這篇文章主要為大家介紹了Python輸入與輸出,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2021-12-12
  • Python使用tkinter實現搖骰子小游戲功能的代碼

    Python使用tkinter實現搖骰子小游戲功能的代碼

    這篇文章主要介紹了Python使用tkinter實現的搖骰子小游戲功能,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-07-07
  • 如何在Windows環(huán)境下安裝PyMySQL(已安裝Anaconda)

    如何在Windows環(huán)境下安裝PyMySQL(已安裝Anaconda)

    這篇文章主要介紹了如何在Windows環(huán)境下安裝PyMySQL問題(已安裝Anaconda),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • Python大數據之網絡爬蟲的post請求、get請求區(qū)別實例分析

    Python大數據之網絡爬蟲的post請求、get請求區(qū)別實例分析

    這篇文章主要介紹了Python大數據之網絡爬蟲的post請求、get請求區(qū)別,結合具體實例形式分析了Python網頁爬蟲post請求與get請求相關使用技巧,需要的朋友可以參考下
    2019-11-11
  • citespace數據處理:用python對Ref文檔進行去重方式

    citespace數據處理:用python對Ref文檔進行去重方式

    這篇文章主要介紹了citespace數據處理:用python對Ref文檔進行去重方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • python使用xslt提取網頁數據的方法

    python使用xslt提取網頁數據的方法

    這篇文章主要為大家詳細介紹了Python使用xslt提取網頁數據的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-02-02
  • 使用Python實現圖片轉ICO格式

    使用Python實現圖片轉ICO格式

    這篇文章主要為大家詳細介紹了如何使用Python編寫一個基于PyQt5的用于將圖像文件轉換為ICO格式GUI應用程序,感興趣的小伙伴可以跟隨小編一起學習一下
    2025-01-01
  • python?groupby函數實現分組選取最大值與最小值

    python?groupby函數實現分組選取最大值與最小值

    這篇文章主要介紹了python?groupby函數實現分組選取最大值與最小值,文章圍繞主題展開詳細的內容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-08-08
  • python 內置模塊詳解

    python 內置模塊詳解

    模塊是一個保存了Python代碼的文件。模塊能定義函數,類和變量。模塊里也能包含可執(zhí)行的代碼,今天我們就來詳細探討下python內置的一些常用模塊
    2019-01-01

最新評論

长顺县| 洪洞县| 平果县| 德阳市| 洛川县| 哈巴河县| 宣化县| 北川| 自贡市| 内乡县| 乌兰浩特市| 昌平区| 延安市| 龙山县| 孝义市| 万宁市| 南城县| 宝清县| 蓬安县| 金寨县| 克什克腾旗| 太仆寺旗| 永平县| 南靖县| 伊金霍洛旗| 察哈| 连江县| 西藏| 芜湖县| 镇安县| 鸡泽县| 南乐县| 乌鲁木齐县| 亳州市| 陆丰市| 邯郸市| 兴化市| 泸西县| 浑源县| 抚远县| 西平县|