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

參考:

如何創(chuàng)建一個(gè)進(jìn)程
實(shí)際上敢靡,當(dāng)計(jì)算機(jī)開機(jī)的時(shí)候挂滓,內(nèi)核(kernel)只建立了一個(gè)init進(jìn)程。Linux內(nèi)核并不提供直接建立新進(jìn)程的系統(tǒng)調(diào)用啸胧。剩下的所有進(jìn)程都是init進(jìn)程通過fork機(jī)制建立的赶站。新的進(jìn)程要通過老的進(jìn)程復(fù)制自身得到,這就是fork纺念。fork是一個(gè)系統(tǒng)調(diào)用贝椿。進(jìn)程存活于內(nèi)存中。每個(gè)進(jìn)程都在內(nèi)存中分配有屬于自己的一片空間 (address space)陷谱。當(dāng)進(jìn)程fork的時(shí)候烙博,Linux在內(nèi)存中開辟出一片新的內(nèi)存空間給新的進(jìn)程瑟蜈,并將老的進(jìn)程空間中的內(nèi)容復(fù)制到新的空間中,此后兩個(gè)進(jìn)程同時(shí)運(yùn)行渣窜。

老進(jìn)程成為新進(jìn)程的父進(jìn)程(parent process)铺根,而相應(yīng)的,新進(jìn)程就是老的進(jìn)程的子進(jìn)程(child process)乔宿。一個(gè)進(jìn)程除了有一個(gè)PID之外位迂,還會(huì)有一個(gè)PPID(parent PID)來存儲(chǔ)的父進(jìn)程PID。如果我們循著PPID不斷向上追溯的話详瑞,總會(huì)發(fā)現(xiàn)其源頭是init進(jìn)程掂林。所以說,所有的進(jìn)程也構(gòu)成一個(gè)以init為根的樹狀結(jié)構(gòu)蛤虐。

ork通常作為一個(gè)函數(shù)被調(diào)用党饮。這個(gè)函數(shù)會(huì)有兩次返回,將子進(jìn)程的PID返回給父進(jìn)程驳庭,0返回給子進(jìn)程刑顺。實(shí)際上,子進(jìn)程總可以查詢自己的PPID來知道自己的父進(jìn)程是誰饲常,這樣蹲堂,一對(duì)父進(jìn)程和子進(jìn)程就可以隨時(shí)查詢對(duì)方。

通常在調(diào)用fork函數(shù)之后贝淤,程序會(huì)設(shè)計(jì)一個(gè)if選擇結(jié)構(gòu)柒竞。當(dāng)PID等于0時(shí),說明該進(jìn)程為子進(jìn)程播聪,那么讓它執(zhí)行某些指令,比如說使用exec庫函數(shù)(library function)讀取另一個(gè)程序文件朽基,并在當(dāng)前的進(jìn)程空間執(zhí)行 (這實(shí)際上是我們使用fork的一大目的: 為某一程序創(chuàng)建進(jìn)程);而當(dāng)PID為一個(gè)正整數(shù)時(shí)离陶,說明為父進(jìn)程稼虎,則執(zhí)行另外一些指令。由此招刨,就可以在子進(jìn)程建立之后霎俩,讓它執(zhí)行與父進(jìn)程不同的功能。

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

詳細(xì)參見: 《AdvancedProgrammingin The Unix Environment》Section 13.3 Page 583
1沉眶、調(diào)用umask將文件模式創(chuàng)建屏蔽字設(shè)置為一個(gè)已知值(通常是0)打却。如前所述,由繼承得來的文件模式創(chuàng)建屏蔽字可能會(huì)被設(shè)置為拒絕權(quán)限谎倔。我們可以根據(jù)我們的具體需求設(shè)定特定的權(quán)限柳击。
2、調(diào)用fork片习,然后使父進(jìn)程exit腻暮。這樣做彤守,使得當(dāng)我們以./的shell命令啟動(dòng)守護(hù)進(jìn)程時(shí),父進(jìn)程終止會(huì)讓shell認(rèn)為此命令已經(jīng)執(zhí)行完畢哭靖,而且,這也使子進(jìn)程獲得了一個(gè)新的進(jìn)程ID侈离。此外试幽,讓父進(jìn)程先于子進(jìn)程exit,會(huì)使子進(jìn)程變?yōu)楣聝哼M(jìn)程卦碾,這樣子進(jìn)程成功被init這個(gè)用戶級(jí)守護(hù)進(jìn)程收養(yǎng)铺坞。
3、調(diào)用setsid創(chuàng)建一個(gè)新會(huì)話洲胖。這在setsid函數(shù)中有介紹济榨,調(diào)用setsid,會(huì)使這個(gè)子進(jìn)程成為(a)新會(huì)話的首進(jìn)程绿映,(b)成為一個(gè)新進(jìn)程組的組長進(jìn)程擒滑,(c)切斷其與控制終端的聯(lián)系,或者就是沒有控制終端叉弦。至此丐一,這個(gè)子進(jìn)程作為新的進(jìn)程組的組長,完全脫離了其他進(jìn)程的控制淹冰,并且沒有控制終端库车。
4、將當(dāng)前工作目錄更改為根目錄(或某一特定目錄位置)樱拴。這是為了保證守護(hù)進(jìn)程的當(dāng)前工作目錄在一個(gè)掛載的文件系統(tǒng)中柠衍,該文件系統(tǒng)不能被卸載。
5晶乔、關(guān)閉不再需要的文件描述符珍坊。根據(jù)具體情況來定。
6瘪弓、某些守護(hù)進(jìn)程可以打開/dev/null使其具有文件描述符0垫蛆、1、2腺怯,這使任何一個(gè)試圖讀標(biāo)準(zhǔn)輸入袱饭、寫標(biāo)準(zhǔn)輸出或標(biāo)準(zhǔn)錯(cuò)誤的庫例程都不會(huì)產(chǎn)生任何效果。
7呛占、忽略SIGCHLD信號(hào)
這一步并非必須的虑乖,只對(duì)需要?jiǎng)?chuàng)建子進(jìn)程的守護(hù)進(jìn)程才有必要,很多服務(wù)器守護(hù)進(jìn)程設(shè)計(jì)成通過派生子進(jìn)程來處理客戶端的請(qǐng)求晾虑,如果父進(jìn)程不對(duì)SIGCHLD信號(hào)進(jìn)行處理的話疹味,子進(jìn)程在終止后變成僵尸進(jìn)程仅叫,通過將信號(hào)SIGCHLD的處理方式設(shè)置為SIG_IGN可以避免這種情況發(fā)生。
8糙捺、用日志系統(tǒng)記錄出錯(cuò)信息
因?yàn)槭刈o(hù)進(jìn)程沒有控制終端诫咱,當(dāng)進(jìn)程出現(xiàn)錯(cuò)誤時(shí)無法寫入到標(biāo)準(zhǔn)輸出上,可以通過調(diào)用syslog將出錯(cuò)信息寫入到指定的文件中洪灯。該接口函數(shù)包括openlog坎缭、syslog、closelog签钩、setlogmask掏呼,具體可參考13.4節(jié)出錯(cuò)記錄。
9铅檩、守護(hù)進(jìn)程退出處理
當(dāng)用戶需要外部停止守護(hù)進(jìn)程運(yùn)行時(shí)憎夷,往往會(huì)使用 kill命令停止該守護(hù)進(jìn)程。所以昧旨,守護(hù)進(jìn)程中需要編碼來實(shí)現(xiàn)kill發(fā)出的signal信號(hào)處理拾给,達(dá)到進(jìn)程的正常退出。

總結(jié)守護(hù)進(jìn)程編程規(guī)則

  • 1.在后臺(tái)運(yùn)行臼予,調(diào)用fork 鸣戴,然后使父進(jìn)程exit
  • 2.脫離控制終端,登錄會(huì)話和進(jìn)程組粘拾,調(diào)用setsid()使進(jìn)程成為會(huì)話組長
  • 3.禁止進(jìn)程重新打開控制終端
  • 4.關(guān)閉打開的文件描述符窄锅,調(diào)用fclose()
  • 5.將當(dāng)前工作目錄更改為根目錄。
  • 6.重設(shè)文件創(chuàng)建掩碼為0
  • 7.處理SIGCHLD 信號(hào)

Python代碼實(shí)現(xiàn)



#!/usr/bin/env python  
# coding:utf-8  
import os,sys,time  

def daemon_init(stdin='/dev/null',stdout='/dev/null',stderr='/dev/null'):
    sys.stdin = open(stdin,'r')
    sys.stdout = open(stdout,'a+')
    sys.stderr = open(stderr,'a+')
    
    try:
        pid = os.fork()
        if pid > 0: # judge if pid is parent id
            os._exit(0) # kill parent id
    except  OSError as e:
        sys.stderr.write("first fork failed!!"+e.strerror)
        os._exit(1)
   # 子進(jìn)程缰雇, 由于父進(jìn)程已經(jīng)退出入偷,所以子進(jìn)程變?yōu)楣聝哼M(jìn)程,由init收養(yǎng)  
'''setsid使子進(jìn)程成為新的會(huì)話首進(jìn)程械哟,和進(jìn)程組的組長疏之,與原來的進(jìn)程組、控制終端和登錄會(huì)話脫離暇咆。'''  
     os.setsid()
     '''防止在類似于臨時(shí)掛載的文件系統(tǒng)下運(yùn)行锋爪,例如/mnt文件夾下,這樣守護(hù)進(jìn)程一旦運(yùn)行爸业,臨時(shí)掛載的文件系統(tǒng)就無法卸載了其骄,這里我們推薦把當(dāng)前工作目錄切換到根目錄下'''
     os.chdir("/")
     '''設(shè)置用戶創(chuàng)建文件的默認(rèn)權(quán)限,設(shè)置的是權(quán)限“補(bǔ)碼”扯旷,這里將文件權(quán)限掩碼設(shè)為0拯爽,使得用戶創(chuàng)建的文件具有最大的權(quán)限。否則钧忽,默認(rèn)權(quán)限是從父進(jìn)程繼承得來的'''  
     os.umask(0)
     
     try:
        pid = os.fork() #第二次進(jìn)行fork,為了防止會(huì)話首進(jìn)程意外獲得控制終端 
        if pid>0:
            os._exit(0) #父進(jìn)程退出
     except OSError as e:
        sys.stderr.write("second fork failed"+e.strerror)
     sys.stdout.write("Daemon has been created! with pid: %d\n" % os.getpid())  
     sys.stdout.flush()  #由于這里我們使用的是標(biāo)準(zhǔn)IO毯炮,回顧APUE第五章逼肯,這里應(yīng)該是行緩沖或全緩沖,因此要調(diào)用flush桃煎,從內(nèi)存中刷入日志文件篮幢。  

def main():  
    print '========main function start!============' #在調(diào)用daemon_init函數(shù)前是可以使用print到標(biāo)準(zhǔn)輸出的,調(diào)用之后就要用把提示信息通過stdout發(fā)送到日志系統(tǒng)中了  
    daemon_init('/dev/null','/tmp/daemon.log','/tmp/daemon.err')    # 調(diào)用之后为迈,你的程序已經(jīng)成為了一個(gè)守護(hù)進(jìn)程洲拇,可以執(zhí)行自己的程序入口了  
    time.sleep(10) #daemon化自己的程序之后,sleep 10秒曲尸,模擬阻塞  
  
  
if __name__ == '__main__':  
    main()  

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市男翰,隨后出現(xiàn)的幾起案子另患,更是在濱河造成了極大的恐慌,老刑警劉巖蛾绎,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件昆箕,死亡現(xiàn)場離奇詭異,居然都是意外死亡租冠,警方通過查閱死者的電腦和手機(jī)鹏倘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來顽爹,“玉大人纤泵,你說我怎么就攤上這事【翟粒” “怎么了捏题?”我有些...
    開封第一講書人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長肉渴。 經(jīng)常有香客問我公荧,道長,這世上最難降的妖魔是什么同规? 我笑而不...
    開封第一講書人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任循狰,我火速辦了婚禮,結(jié)果婚禮上券勺,老公的妹妹穿的比我還像新娘绪钥。我一直安慰自己,他們只是感情好朱灿,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開白布昧识。 她就那樣靜靜地躺著,像睡著了一般盗扒。 火紅的嫁衣襯著肌膚如雪跪楞。 梳的紋絲不亂的頭發(fā)上缀去,一...
    開封第一講書人閱讀 52,246評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音甸祭,去河邊找鬼缕碎。 笑死,一個(gè)胖子當(dāng)著我的面吹牛池户,可吹牛的內(nèi)容都是我干的咏雌。 我是一名探鬼主播,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼校焦,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼赊抖!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起寨典,我...
    開封第一講書人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤氛雪,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后耸成,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體报亩,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年井氢,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了弦追。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡花竞,死狀恐怖劲件,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情左胞,我是刑警寧澤寇仓,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站烤宙,受9級(jí)特大地震影響遍烦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜躺枕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一服猪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧拐云,春花似錦罢猪、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春危彩,著一層夾襖步出監(jiān)牢的瞬間攒磨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來泰國打工汤徽, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留娩缰,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓谒府,卻偏偏與公主長得像拼坎,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子完疫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • Linux 進(jìn)程管理與程序開發(fā) 進(jìn)程是Linux事務(wù)管理的基本單元泰鸡,所有的進(jìn)程均擁有自己獨(dú)立的處理環(huán)境和系統(tǒng)資源,...
    JamesPeng閱讀 2,471評(píng)論 1 14
  • 又來到了一個(gè)老生常談的問題壳鹤,應(yīng)用層軟件開發(fā)的程序員要不要了解和深入學(xué)習(xí)操作系統(tǒng)呢鸟顺? 今天就這個(gè)問題開始,來談?wù)劜?..
    tangsl閱讀 4,134評(píng)論 0 23
  • 蹣跚步器虾,君回首,次察先覺淋漓滿屋斗蹦锋。陰雨后兆沙,多望君驚笑。人不寐莉掂,花夜放葛圃。 誰道少年無情懷,四海皆為家憎妙。...
    我思佳人閱讀 217評(píng)論 0 1
  • 人生是一場無法回頭的旅行 既然選擇了異鄉(xiāng) 孤獨(dú)厘唾!漂泊褥符! 以及其它七情六欲,八十一難抚垃! 來看看吧喷楣,看清我真正的面目 ...
    漸行漸遠(yuǎn)漸有知閱讀 801評(píng)論 3 3
  • 就在剛剛,我試圖去吃些東西鹤树,肚子吵的我有些煩了铣焊。我穿著好幾天沒換的衣服,晃晃悠悠的走在大街上罕伯。最近風(fēng)比以往大了些曲伊,...
    落寞的藍(lán)閱讀 182評(píng)論 0 0