<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    一江春水向東流

    做一個(gè)有思想的人,期待與每一位熱愛思考的人交流,您的關(guān)注是對(duì)我最大的支持。

      BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      44 隨筆 :: 139 文章 :: 81 評(píng)論 :: 0 Trackbacks

    編寫Linux/Unix守護(hù)進(jìn)程 [zz]

    守護(hù)進(jìn)程在Linux/Unix系統(tǒng)中有著廣泛的應(yīng)用。有時(shí),開發(fā)人員也想把自己的程序變成守護(hù)進(jìn)程。在創(chuàng)建一個(gè)守護(hù)進(jìn)程的時(shí)候,要接觸到子進(jìn)程、進(jìn)程組、會(huì)晤期、信號(hào)機(jī)制、文件、目錄和控制終端等多個(gè)概念。因此守護(hù)進(jìn)程還是比較復(fù)雜的,在這里詳細(xì)地討論Linux/Unix的守護(hù)進(jìn)程的編寫,總結(jié)出八條經(jīng)驗(yàn),并給出應(yīng)用范例。

    ?編程要點(diǎn)

    ????1.屏蔽一些有關(guān)控制終端操作的信號(hào)。防止在守護(hù)進(jìn)程沒有正常運(yùn)轉(zhuǎn)起來(lái)時(shí),控制終端受到干擾退出或掛起。示例如下:

    signal(SIGTTOU,SIG_IGN); 
    signal(SIGTTIN,SIG_IGN); 
    signal(SIGTSTP,SIG_IGN); 
    signal(SIGHUP ,SIG_IGN);/PRE>
    BR>
    ????所有的信號(hào)都有自己的名字。這些名字都以“SIG”開頭,只是后面有所不同。開發(fā)人員可以通過(guò)這些名字了解到系統(tǒng)中發(fā)生了什么事。當(dāng)信號(hào)出現(xiàn)時(shí),開發(fā)人員可以要求系統(tǒng)進(jìn)行以下三種操作:
    ????◆ 忽略信號(hào)。大多數(shù)信號(hào)都是采取這種方式進(jìn)行處理的,這里就采用了這種用法。但值得注意的是對(duì)SIGKILL和SIGSTOP信號(hào)不能做忽略處理。
    ????◆ 捕捉信號(hào)。最常見的情況就是,如果捕捉到SIGCHID信號(hào),則表示子進(jìn)程已經(jīng)終止。然后可在此信號(hào)的捕捉函數(shù)中調(diào)用waitpid()函數(shù)取得該子進(jìn)程的進(jìn)程ID和它的終止?fàn)顟B(tài)。另外,如果進(jìn)程創(chuàng)建了臨時(shí)文件,那么就要為進(jìn)程終止信號(hào)SIGTERM編寫一個(gè)信號(hào)捕捉函數(shù)來(lái)清除這些臨時(shí)文件。
    ????◆ 執(zhí)行系統(tǒng)的默認(rèn)動(dòng)作。對(duì)絕大多數(shù)信號(hào)而言,系統(tǒng)的默認(rèn)動(dòng)作都是終止該進(jìn)程。

    ????對(duì)這些有關(guān)終端的信號(hào),一般采用忽略處理,從而保障了終端免受干擾。

    ????這類信號(hào)分別是,SIGTTOU(表示后臺(tái)進(jìn)程寫控制終端)、SIGTTIN(表示后臺(tái)進(jìn)程讀控制終端)、SIGTSTP(表示終端掛起)和SIGHUP(進(jìn)程組長(zhǎng)退出時(shí)向所有會(huì)議成員發(fā)出的)。

    ????2.將程序進(jìn)入后臺(tái)執(zhí)行。由于守護(hù)進(jìn)程最終脫離控制終端,到后臺(tái)去運(yùn)行。方法是在進(jìn)程中調(diào)用fork使父進(jìn)程終止,讓Daemon在子進(jìn)程中后臺(tái)執(zhí)行。這就是常說(shuō)的“脫殼”。子進(jìn)程繼續(xù)函數(shù)fork()的定義如下:

    #include <sys/types.h>
    #include <unistd.h>
     pid_t fork(void);/PRE>
    BR>
    ????該函數(shù)是Linux/Unix編程中非常重要的函數(shù)。它被調(diào)用一次,但返回兩次。這兩次返回的區(qū)別是子進(jìn)程的返回值為“0”,而父進(jìn)程的返回值為子進(jìn)程的ID。如果出錯(cuò)則返回“-1”。

    ????3.脫離控制終端、登錄會(huì)話和進(jìn)程組。開發(fā)人員如果要擺脫它們,不受它們的影響,一般使用 setsid() 設(shè)置新會(huì)話的領(lǐng)頭進(jìn)程,并與原來(lái)的登錄會(huì)話和進(jìn)程組脫離。這只是其中的一種方法,也有如下處理的辦法:

    if  ((fd = open("/dev/tty",O_RDWR)) >= 0) { 
    ioctl(fd,TIOCNOTTY,NULL); 
    close(fd); 
    }/PRE>
    BR>
    ????其中/dev/tty是一個(gè)流設(shè)備,也是終端映射,調(diào)用close()函數(shù)將終端關(guān)閉。

    ????4.禁止進(jìn)程重新打開控制終端。進(jìn)程已經(jīng)成為無(wú)終端的會(huì)話組長(zhǎng),但它可以重新申請(qǐng)打開一個(gè)控制終端。開發(fā)人員可以通過(guò)不再讓進(jìn)程成為會(huì)話組長(zhǎng)的方式來(lái)禁止進(jìn)程重新打開控制終端,需要再次調(diào)用fork函數(shù)。
    ????上面的程序代碼表示結(jié)束第一子進(jìn)程,第二子進(jìn)程繼續(xù)(第二子進(jìn)程不再是會(huì)話組長(zhǎng))。

    ????5. 關(guān)閉打開的文件描述符,并重定向標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤輸出的文件描述符。進(jìn)程從創(chuàng)建它的父進(jìn)程那里繼承了打開的文件描述符。如果不關(guān)閉,將會(huì)浪費(fèi)系統(tǒng)資源,引起無(wú)法預(yù)料的錯(cuò)誤。關(guān)閉三者的代碼如下:

    for (fd = 0, fdtablesize = getdtablesize(); 
     fd < fdtablesize; fd++) 
      close(fd);/PRE>
    BR>
    ????但標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤輸出的重定向是可選的。也許有的程序想保留標(biāo)準(zhǔn)輸入(0)、標(biāo)準(zhǔn)輸出(1)和標(biāo)準(zhǔn)錯(cuò)誤輸出(2),那么循環(huán)應(yīng)繞過(guò)這三者。代碼如下:

    for (fd =3, fdtablesize = getdtablesize();
    fd < fdtablesize; fd++) 
      close(fd);/PRE>
    BR>
    ????有的程序有些特殊的需求,還需要將這三者重新定向。示例如下:

    error=open("/tmp/error",O_WRONLY|O_CREAT,
    0600);
      dup2(error,2);
     close(error);
     in=open("/tmp/in",O_RDONLY|O_CREAT,0600);
     if(dup2(in,0)==-1)  perror("in");
     close(in);
    out=open("/tmp/out",O_WRONLY|O_CREAT,0600);
     if(dup2(out,1)==-1) perror("out");
     close(out);/PRE>
    BR>
    ????6.改變工作目錄到根目錄或特定目錄進(jìn)程活動(dòng)時(shí),其工作目錄所在的文件系統(tǒng)不能卸下。

    ????一般需要將工作目錄改變到根目錄或特定目錄,注意用戶對(duì)此目錄需要有讀寫權(quán)。防止超級(jí)用戶卸載設(shè)備時(shí)系統(tǒng)報(bào)告設(shè)備忙。

    ????7.處理SIGCHLD信號(hào)。SIGCHLD信號(hào)是子進(jìn)程結(jié)束時(shí),向內(nèi)核發(fā)送的信號(hào)。

    如果父進(jìn)程不等待子進(jìn)程結(jié)束,子進(jìn)程將成為僵尸進(jìn)程(zombie)從而占用系統(tǒng)資源。因此需要對(duì)SIGCHLD信號(hào)做出處理,回收僵尸進(jìn)程的資源,避免造成不必要的資源浪費(fèi)??梢杂萌缦抡Z(yǔ)句:
    ????signal(SIGCHLD,(void *)reap_status);

    ????捕捉信號(hào)SIGCHLD,用下面的函數(shù)進(jìn)行處理:

    void reap_status() 
     { int pid; 
       union wait status; 
       while ((pid = wait3(&status,WNOHANG,NULL)) > 0) 
      …… }/PRE>
    BR>
    ????8.在Linux/Unix下有個(gè)syslogd的守護(hù)進(jìn)程,向用戶提供了syslog()系統(tǒng)調(diào)用。任何程序都可以通過(guò)syslog記錄事件。

    ????由于syslog非常好用和易配置,所以很多程序都使用syslog來(lái)發(fā)送它們的記錄信息。一般守護(hù)進(jìn)程也使用syslog向系統(tǒng)輸出信息。syslog有三個(gè)函數(shù),一般只需要用syslog(...)函數(shù),openlog()/closelog()可有可無(wú)。syslog()在shslog.h定義如下:

    #include <syslog.h>
    void syslog(int priority,char *format,...);/PRE>
    BR>
    ????其中參數(shù)priority指明了進(jìn)程要寫入信息的等級(jí)和用途。第二個(gè)參數(shù)是一個(gè)格式串,指定了記錄輸出的格式。在這個(gè)串的最后需要指定一個(gè)%m,對(duì)應(yīng)errno錯(cuò)誤碼。

    ????應(yīng)用范例

    ????下面給出Linux下編程的守護(hù)進(jìn)程的應(yīng)用范例,在UNIX中,不同版本實(shí)現(xiàn)的細(xì)節(jié)可能不一致,但其實(shí)現(xiàn)的原則是與Linux一致的。

    #include <stdio.h> 
    #include <signal.h> 
    #include <sys/file.h> 
    main(int argc,char **argv)
    {
      time_t now;
      int childpid,fd,fdtablesize;
      int error,in,out;
      /* 忽略終端 I/O信號(hào),STOP信號(hào) */
     signal(SIGTTOU,SIG_IGN);
     signal(SIGTTIN,SIG_IGN);
      signal(SIGTSTP,SIG_IGN); 
      signal(SIGHUP ,SIG_IGN);
      /* 父進(jìn)程退出,程序進(jìn)入后臺(tái)運(yùn)行 */
      if(fork()!=0) exit(1);
       if(setsid()<0)exit(1);/* 創(chuàng)建一個(gè)新的會(huì)議組 */ 
      /* 子進(jìn)程退出,孫進(jìn)程沒有控制終端了 */  
      if(fork()!=0) exit(1);
      if(chdir("/tmp")==-1)exit(1);
    /* 關(guān)閉打開的文件描述符,包括標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤輸出 */ 
     for (fd = 0, fdtablesize = getdtablesize(); fd < fdtablesize; fd++) 
       close(fd);
       umask(0);/*重設(shè)文件創(chuàng)建掩模 */ 
       signal(SIGCHLD,SIG_IGN);/* 忽略SIGCHLD信號(hào) */ 
    /*打開log系統(tǒng)*/
      syslog(LOG_USER|LOG_INFO,"守護(hù)進(jìn)程測(cè)試!n");  
       while(1)  
       {  
        time(&now);
       syslog(LOG_USER|LOG_INFO,"當(dāng)前時(shí)間:t%sttn",ctime(&now));
        sleep(6);
         }  
     }/PRE>
    BR>
    ????此程序在Turbo Linux 4.0下編譯通過(guò)。這個(gè)程序比較簡(jiǎn)單,但基本體現(xiàn)了守護(hù)進(jìn)程的編程要點(diǎn)。讀者針對(duì)實(shí)際應(yīng)用中不同的需要,還可以做相應(yīng)的調(diào)整。
    posted on 2007-04-13 14:04 allic 閱讀(983) 評(píng)論(0)  編輯  收藏 所屬分類: linux/UNIX 應(yīng)用開發(fā)
    主站蜘蛛池模板: 中文精品人人永久免费| 亚洲国产成人久久一区WWW| 国产成人精品免费大全| 亚洲 欧洲 日韩 综合在线| 亚洲AV无码专区电影在线观看 | 少妇中文字幕乱码亚洲影视| 亚洲成AV人在线观看网址| 成人看的午夜免费毛片| 91精品全国免费观看含羞草| 久久嫩草影院免费看夜色| 色欲aⅴ亚洲情无码AV| 亚洲人成影院午夜网站| 久久精品国产亚洲香蕉| 国产自偷亚洲精品页65页| 亚洲欧洲国产成人综合在线观看| 青青青国产免费一夜七次郎| 国产在线观看免费观看不卡| 18成禁人视频免费网站| 久久午夜免费鲁丝片| 国产免费网站看v片在线| eeuss影院免费92242部| 免费无码午夜福利片69| 精品韩国亚洲av无码不卡区| 亚洲综合精品伊人久久| 亚洲一区二区三区高清不卡| 亚洲婷婷天堂在线综合| 亚洲男女性高爱潮网站| 日韩亚洲Av人人夜夜澡人人爽| 久久亚洲精品成人| 久久精品亚洲综合专区| 亚洲乱码精品久久久久..| 亚洲一区爱区精品无码| 亚洲色成人中文字幕网站| 亚洲色爱图小说专区| 久久国产亚洲电影天堂| 亚洲色av性色在线观无码| 亚洲高清视频免费| 亚洲午夜国产精品| 亚洲香蕉在线观看| 亚洲av乱码中文一区二区三区| 久久久久久久久无码精品亚洲日韩|