自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

使用PHP腳本來(lái)寫(xiě)Daemon程序

開(kāi)發(fā) 后端 前端
為什么一定要使用daemon進(jìn)程呢?Linux中每一個(gè)系統(tǒng)與用戶(hù)進(jìn)行交流的界面稱(chēng)為終端(terminal),每一個(gè)從此終端開(kāi)始運(yùn)行的進(jìn)程都會(huì)依附于這個(gè)終端,這個(gè)終端就稱(chēng)為這些進(jìn)程的控制終端(Controlling terminal),當(dāng)控制終端被關(guān)閉時(shí),相應(yīng)的進(jìn)程都會(huì)被自動(dòng)關(guān)閉。

這又是一個(gè)有趣的概念,daemon在英語(yǔ)中是"精靈"的意思,就像我們經(jīng)常在迪斯尼動(dòng)畫(huà)里見(jiàn)到的那些,有些會(huì)飛,有些不會(huì),經(jīng)常圍著動(dòng)畫(huà)片的主人公轉(zhuǎn)來(lái)轉(zhuǎn)去,啰里啰唆地提一些忠告,時(shí)不時(shí)倒霉地撞在柱子上,有時(shí)候還會(huì)想出一些小小的花招,把主人公從敵人手中救出來(lái),正因如此,daemon有時(shí)也被譯作"守護(hù)神"。所以,daemon進(jìn)程在國(guó)內(nèi)也有兩種譯法,有些人譯作"精靈進(jìn)程",有些人譯作"守護(hù)進(jìn)程",這兩種稱(chēng)呼的出現(xiàn)頻率都很高。

與真正的daemon相似,daemon進(jìn)程也習(xí)慣于把自己隱藏在人們的視線(xiàn)之外,默默為系統(tǒng)做出貢獻(xiàn),有時(shí)人們也把它們稱(chēng)作"后臺(tái)服務(wù)進(jìn)程"。daemon進(jìn)程的壽命很長(zhǎng),一般來(lái)說(shuō),從它們一被執(zhí)行開(kāi)始,直到整個(gè)系統(tǒng)關(guān)閉,它們才會(huì)退出。幾乎所有的服務(wù)器程序,包括我們熟知的Apache和wu-FTP,都用daemon進(jìn)程的形式實(shí)現(xiàn)。很多Linux下常見(jiàn)的命令如inetd和ftpd,末尾的字母d就是指daemon。

為什么一定要使用daemon進(jìn)程呢?Linux中每一個(gè)系統(tǒng)與用戶(hù)進(jìn)行交流的界面稱(chēng)為終端(terminal),每一個(gè)從此終端開(kāi)始運(yùn)行的進(jìn)程都會(huì)依附于這個(gè)終端,這個(gè)終端就稱(chēng)為這些進(jìn)程的控制終端(Controlling terminal),當(dāng)控制終端被關(guān)閉時(shí),相應(yīng)的進(jìn)程都會(huì)被自動(dòng)關(guān)閉。關(guān)于這點(diǎn),讀者可以用X-Window中的XTerm試驗(yàn)一下,(每一個(gè)XTerm就是一個(gè)打開(kāi)的終端,)我們可以通過(guò)鍵入命令啟動(dòng)應(yīng)用程序,比如:$netscape 然后我們關(guān)閉XTerm窗口,剛剛啟動(dòng)的netscape窗口也會(huì)隨之一同突然蒸發(fā)。但是daemon進(jìn)程卻能夠突破這種限制,即使對(duì)應(yīng)的終端關(guān)閉,它也能在系統(tǒng)中長(zhǎng)久地存在下去,如果我們想讓某個(gè)進(jìn)程長(zhǎng)命百歲,不因?yàn)橛脩?hù)或終端或其他的變化而受到影響,就必須把這個(gè)進(jìn)程變成一個(gè)daemon進(jìn)程。

1. Daemon進(jìn)程的編程規(guī)則

如果想把自己的進(jìn)程變成daemon進(jìn)程,我們必須嚴(yán)格按照以下步驟進(jìn)行:

1、調(diào)用fork產(chǎn)生一個(gè)子進(jìn)程,同時(shí)父進(jìn)程退出。我們所有后續(xù)工作都在子進(jìn)程中完成。這樣做我們可以:

1.1 如果我們是從命令行執(zhí)行的該程序,這可以造成程序執(zhí)行完畢的假象,shell會(huì)回去等待下一條命令;

1.2 剛剛通過(guò)fork產(chǎn)生的新進(jìn)程一定不會(huì)是一個(gè)進(jìn)程組的組長(zhǎng),這為第2步的執(zhí)行提供了前提保障。

這樣做還會(huì)出現(xiàn)一種很有趣的現(xiàn)象:由于父進(jìn)程已經(jīng)先于子進(jìn)程退出,會(huì)造成子進(jìn)程沒(méi)有父進(jìn)程,變成一個(gè)孤兒進(jìn)程(orphan)。每當(dāng)系統(tǒng)發(fā)現(xiàn)一個(gè)孤兒進(jìn)程,就會(huì)自動(dòng)由1號(hào)進(jìn)程收養(yǎng)它,這樣,原先的子進(jìn)程就會(huì)變成1號(hào)進(jìn)程的子進(jìn)程。

2、調(diào)用setsid系統(tǒng)調(diào)用。

這是整個(gè)過(guò)程中最重要的一步。setsid的介紹見(jiàn)附錄2,它的作用是創(chuàng)建一個(gè)新的會(huì)話(huà)(session),并自任該會(huì)話(huà)的組長(zhǎng)(session leader)。如果調(diào)用進(jìn)程是一個(gè)進(jìn)程組的組長(zhǎng),調(diào)用就會(huì)失敗,但這已經(jīng)在第1步得到了保證。調(diào)用setsid有3個(gè)作用:

2.1 讓進(jìn)程擺脫原會(huì)話(huà)的控制;

2.2 讓進(jìn)程擺脫原進(jìn)程組的控制;

2.3 讓進(jìn)程擺脫原控制終端的控制;

總之,就是讓調(diào)用進(jìn)程完全獨(dú)立出來(lái),脫離所有其他進(jìn)程的控制。

3、把當(dāng)前工作目錄切換到根目錄。

如果我們是在一個(gè)臨時(shí)加載的文件系統(tǒng)上執(zhí)行這個(gè)進(jìn)程的,比如:/mnt/floppy/,該進(jìn)程的當(dāng)前工作目錄就會(huì)是/mnt/floppy/。在整個(gè)進(jìn)程運(yùn)行期間該文件系統(tǒng)都無(wú)法被卸下(umount),而無(wú)論我們是否在使用這個(gè)文件系統(tǒng),這會(huì)給我們帶來(lái)很多不便。解決的方法是使用chdir系統(tǒng)調(diào)用把當(dāng)前工作目錄變?yōu)楦夸?,?yīng)該不會(huì)有人想把根目錄卸下吧。

關(guān)于chdir的用法,參見(jiàn)附錄1。

當(dāng)然,在這一步里,如果有特殊的需要,我們也可以把當(dāng)前工作目錄換成其他的路徑,比如/tmp。

4、將文件權(quán)限掩碼設(shè)為0。

這需要調(diào)用系統(tǒng)調(diào)用umask,參見(jiàn)附錄3。每個(gè)進(jìn)程都會(huì)從父進(jìn)程那里繼承一個(gè)文件權(quán)限掩碼,當(dāng)創(chuàng)建新文件時(shí),這個(gè)掩碼被用于設(shè)定文件的默認(rèn)訪問(wèn)權(quán)限,屏蔽掉某些權(quán)限,如一般用戶(hù)的寫(xiě)權(quán)限。當(dāng)另一個(gè)進(jìn)程用exec調(diào)用我們編寫(xiě)的daemon程序時(shí),由于我們不知道那個(gè)進(jìn)程的文件權(quán)限掩碼是什么,這樣在我們創(chuàng)建新文件時(shí),就會(huì)帶來(lái)一些麻煩。所以,我們應(yīng)該重新設(shè)置文件權(quán)限掩碼,我們可以設(shè)成任何我們想要的值,但一般情況下,大家都把它設(shè)為0,這樣,它就不會(huì)屏蔽用戶(hù)的任何操作。

如果你的應(yīng)用程序根本就不涉及創(chuàng)建新文件或是文件訪問(wèn)權(quán)限的設(shè)定,你也完全可以把文件權(quán)限掩碼一腳踢開(kāi),跳過(guò)這一步。

5、關(guān)閉所有不需要的文件。

同文件權(quán)限掩碼一樣,我們的新進(jìn)程會(huì)從父進(jìn)程那里繼承一些已經(jīng)打開(kāi)了的文件。這些被打開(kāi)的文件可能永遠(yuǎn)不被我們的daemon進(jìn)程讀或?qū)?,但它們一樣消耗系統(tǒng)資源,而且可能導(dǎo)致所在的文件系統(tǒng)無(wú)法卸下。需要指出的是,文件描述符為0、1和2的三個(gè)文件(文件描述符的概念將在下一章介紹),也就是我們常說(shuō)的輸入、輸出和報(bào)錯(cuò)這三個(gè)文件也需要被關(guān)閉。很可能不少讀者會(huì)對(duì)此感到奇怪,難道我們不需要輸入輸出嗎?但事實(shí)是,在上面的第2步后,我們的daemon進(jìn)程已經(jīng)與所屬的控制終端失去了聯(lián)系,我們從終端輸入的字符不可能達(dá)到daemon進(jìn)程,daemon進(jìn)程用常規(guī)的方法(如printf)輸出的字符也不可能在我們的終端上顯示出來(lái)。所以這三個(gè)文件已經(jīng)失去了存在的價(jià)值,也應(yīng)該被關(guān)閉。

使用PHP編寫(xiě)Gearman的Worker守護(hù)進(jìn)程

在我之前的文章中,介紹過(guò)Gearman的使用。在我的項(xiàng)目中,我使用了PHP來(lái)編寫(xiě)一直運(yùn)行的Worker。如果按照Gearman官方推薦的例子,只是簡(jiǎn)單的一個(gè)循環(huán)來(lái)等待任務(wù),會(huì)有一些問(wèn)題,包括:1、當(dāng)代碼進(jìn)行過(guò)修改之后,如何讓代碼的修改生效;2、重啟Worker的時(shí)候,如何保證當(dāng)前的任務(wù)處理完成才重啟。

針對(duì)這個(gè)問(wèn)題,我考慮了以下的解決方法:

1、每次修改完代碼后,Worker需要手工重啟(先殺死然后啟動(dòng))。這個(gè)只能解決重新加載配置文件的問(wèn)題。

2、在Worker中設(shè)置,單次任務(wù)循環(huán)完成后,就對(duì)Worker進(jìn)行重啟。這個(gè)方案的問(wèn)題在于消耗比較大。

3、在Worker中添加一個(gè)退出函數(shù),如果需要Worker退出的時(shí)候,在Client端發(fā)送一個(gè)優(yōu)先級(jí)比較高的退出調(diào)用。這個(gè)需要客戶(hù)端配合,在使用后臺(tái)類(lèi)任務(wù)時(shí),不太適合。

4、在Worker中檢查文件是否發(fā)生變化,如果發(fā)生了變化,退出并重啟自身。

5、為Worker編寫(xiě)信號(hào)控制,接受重啟指令,類(lèi)似于 http restart graceful 指令。

***,結(jié)合4和5兩種方法,可以實(shí)現(xiàn)這樣一個(gè)Daemon,如果配置文件發(fā)生了變化,他就會(huì)自動(dòng)重啟;如果接受到了用戶(hù)的 kill -1 pid 信號(hào),也會(huì)重新啟動(dòng)。

代碼如下:

  1. <?php 
  2.  
  3. declare( ticks = 1 );  
  4. // This case will check the config file regularly, if the config file changed, it will restart it self  
  5. // If you want to restart the daemon gracefully, give it a HUP signal  
  6. // by shiqiang<cocowool@gmail.com> at 2011-12-04  
  7.  
  8. $init_md5 = md5_file( 'config.php');  
  9.  
  10. // register signal handler  
  11. pcntl_signal( SIGALRM, "signal_handler", true );  
  12. pcntl_signal( SIGHUP, 'signal_handler', TRUE );  
  13.  
  14. $job_flag = FALSE;    //Job status flag, to justify if the job has been finished  
  15. $signal_flag = FALSE;    //Signal status flag, to justify whether we received the kill -1 signal  
  16.  
  17. while( 1 ){  
  18.     $job_flag = FALSE;    //Job status flag  
  19.     print "Worker start running ... \n";  
  20.     sleep(5);  
  21.     print "Worker's task done ... \n";  
  22.     $flag = TRUE;    //Job status flag  
  23.     AutoStart( $signal_flag );  
  24. }  
  25.  
  26. function signal_handler( $signal ) {  
  27.     global $job_flag;  
  28.     global $signal_flag;  
  29.  
  30.     switch( $signal ){  
  31.         case SIGQUIT:  
  32.             print date('y-m-d H:i:s', time() ) . " Caught Signal : SIGQUIT - No : $signal \n";  
  33.             exit(0);  
  34.             break;  
  35.         case SIGSTOP:  
  36.             print date('y-m-d H:i:s', time() ) . " Caught Signal : SIGSTOP - No : $signal \n";  
  37.             break;  
  38.         case SIGHUP:  
  39.             print date('y-m-d H:i:s', time() ) . " Caught Signal : SIGHUP - No : $signal \n";  
  40.             if( $flag === TRUE ){  
  41.                 AutoStart( TRUE );  
  42.             }else{  
  43.                 $signal_flag = TRUE;  
  44.             }  
  45.             break;  
  46.         case SIGALRM:  
  47.             print date('y-m-d H:i:s', time() ) . " Caught Signal : SIGALRM - No : $signal \n";  
  48.             //pcntl_exec( '/bin/ls' );  
  49.             pcntl_alarm( 5 );  
  50.             break;  
  51.         default:  
  52.             break;  
  53.     }  
  54. }  
  55.  
  56. function AutoStart( $signal = FALSE, $filename = 'config.php' ){  
  57.     global $init_md5;  
  58.  
  59.     if( $signal || md5_file( $filename ) != $init_md5 ){  
  60.         print "The config file has been changed, we are going to restart. \n";  
  61.         $pid = pcntl_fork();  
  62.         if( $pid == -1 ){  
  63.             print "Fork error \n";  
  64.         }else if( $pid > 0 ){  
  65.             print "Parent exit \n";  
  66.             exit(0);  
  67.         }else{  
  68.             $init_md5 = md5_file( $filename );  
  69.             print "Child continue to run \n";  
  70.         }  
  71.     }  

原文:http://www.cnblogs.com/cocowool/archive/2011/12/04/2275497.html

【編輯推薦】

  1. PHP開(kāi)發(fā)組首位中國(guó)成員及他的Yaf
  2. 大話(huà)PHP之性能
  3. 如果PHP是用英式英語(yǔ)編寫(xiě)的
  4. PHP集成開(kāi)發(fā)工具PHPStorm 3.0發(fā)布
  5. 手把手教你在Ubuntu上安裝Apache、MySql和PHP

 

責(zé)任編輯:陳貽新 來(lái)源: 小狼的世界
相關(guān)推薦

2015-08-10 14:42:40

Explain SheShell 命令

2009-11-18 13:52:30

PHP shell腳本

2021-05-17 15:08:27

PythonWindows背景編程語(yǔ)言

2019-05-20 16:21:51

LinuxShell監(jiān)控磁盤(pán)

2020-06-16 08:44:23

Shell服務(wù)器

2009-03-23 13:08:07

PHP擴(kuò)展PHPJavascript

2011-07-12 17:11:13

PHPSHELL

2016-03-28 10:00:09

Swift命令程序

2011-09-08 14:25:31

2012-11-29 14:44:07

2011-06-22 10:48:35

PHP

2011-11-30 21:56:31

ibmdwXPathPHP

2009-06-15 10:21:07

基于JBossMBean

2009-05-27 14:31:53

NetBeansEclipsPHP

2018-09-19 08:50:45

PySimpleGUIGUIPython

2010-02-26 13:03:31

Python腳本語(yǔ)言

2009-11-30 16:24:24

PHP腳本

2018-04-22 00:04:04

PHP C 代碼數(shù)據(jù)

2022-10-09 14:50:44

Python腳本

2011-08-30 16:31:23

UbuntuXdebug
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)