• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            S.l.e!ep.¢%

            像打了激速一樣,以四倍的速度運(yùn)轉(zhuǎn),開(kāi)心的工作
            簡(jiǎn)單、開(kāi)放、平等的公司文化;尊重個(gè)性、自由與個(gè)人價(jià)值;
            posts - 1098, comments - 335, trackbacks - 0, articles - 1
              C++博客 :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

            如何編寫UNIX DAEMON程序

            Posted on 2011-01-28 21:47 S.l.e!ep.¢% 閱讀(586) 評(píng)論(0)  編輯 收藏 引用 所屬分類: Unix
            如何編寫UNIX DAEMON程序
            分享
            2008-12-04 16:35

            unix 進(jìn)程可以運(yùn)行在前臺(tái)或是后臺(tái),運(yùn)行在前臺(tái)的(9php.com)程序通過(guò)終端與用戶進(jìn)行交互,而后以進(jìn)程是單獨(dú)運(yùn)行的(9php.com),用戶可以查看它的(9php.com)狀態(tài),但不清楚它具體在做什么。我們將運(yùn)行在后臺(tái)的(9php.com)程序叫做"daemon"程序。如常見(jiàn)的(9php.com)httpd,nfsd,sshd都屬于"daemon"程序,要寫這樣的(9php.com)程序,你可能要考慮如下的(9php.com)一些處理。
            1,后臺(tái)運(yùn)行處理
            使用FORK()調(diào)用創(chuàng)建一個(gè)子進(jìn)程,然后讓父進(jìn)程退出。這樣子進(jìn)程就與父進(jìn)程分離了并運(yùn)行在后臺(tái)。
            ? ? i=fork();
            ? ? if (i<0) exit(1); /* fork error */
            ? ? if (i>0) exit(0); /* parent exits */
            ? ? /* child (daemon) continues */

            2,進(jìn)程依賴處理
            每個(gè)子進(jìn)程繼承父進(jìn)程的(9php.com)控制終端,進(jìn)程將會(huì)接收關(guān)聯(lián)終端的(9php.com)信號(hào)。為了防止daemon程序從創(chuàng)建它的(9php.com)進(jìn)程接收信號(hào),必需去除與控制終端的(9php.com)關(guān)聯(lián)。
            在UNIX系統(tǒng)中,進(jìn)程運(yùn)行在一個(gè)進(jìn)程組,子進(jìn)程會(huì)從父進(jìn)程繼承進(jìn)程組,一個(gè)DAEMON進(jìn)程應(yīng)該不依賴于進(jìn)程組的(9php.com)其它進(jìn)程.
              setsid() /* obtain a new process group */
            這個(gè)函數(shù)將DAEMON進(jìn)程放置于一個(gè)新的(9php.com)進(jìn)程組,并去除了與控制終端的(9php.com)關(guān)聯(lián)。
            3,繼承的(9php.com)文件描述符號(hào)和標(biāo)準(zhǔn)I/O處理
            子進(jìn)程會(huì)繼承父進(jìn)程打開(kāi)的(9php.com)文件描述符,這樣會(huì)導(dǎo)致文件描述符資源的(9php.com)浪費(fèi),所以應(yīng)該關(guān)閉所有繼承過(guò)來(lái)的(9php.com)文件描述符。
            ? ? for (i=getdtablesize();i>=0;--i) close(i); /* close all descriptors */
            對(duì)于stdin,stdout,stderr,將它們重定向到/dev/null。
            ? ? i=open("/dev/null",O_RDWR); /* open stdin */
            ? ? dup(i); /* stdout */
            ? ? dup(i); /* stderr */
            由于關(guān)閉了所有文件描述符,上面的(9php.com)操作會(huì)從0開(kāi)始順序產(chǎn)生文件描述符。

            4,文件掩碼處理
            為了安全的(9php.com)考慮,需要將設(shè)置文件掩碼
              umask(027);

            5,運(yùn)行目錄處理
            一個(gè)daemon進(jìn)程應(yīng)該運(yùn)行在一個(gè)固定的(9php.com)目錄,防止用戶在不同的(9php.com)目錄下運(yùn)行程序后找不到相關(guān)的(9php.com)文件。
              chdir("/servers/");

            6,保持單DAEMON進(jìn)程處理
            為了保持單daemon進(jìn)程,防止運(yùn)行多個(gè)daemon進(jìn)程,有效的(9php.com)方式是建立一個(gè)文件,并對(duì)其加鎖,在進(jìn)程退出時(shí)進(jìn)行解鎖。
            ?? lfp=open("exampled.lock",O_RDWR|O_CREAT,0640);
            ? ? if (lfp<0) exit(1); /* can not open */
            ? ? if (lockf(lfp,F(xiàn)_TLOCK,0)<0) exit(0); /* can not lock */
            ? ? /* only first instance continues */

            ? ? sprintf(str,"%d\n",getpid());
            ? ? write(lfp,str,strlen(str)); /* record pid to lockfile */

            7,信號(hào)處理
            對(duì)于daemon進(jìn)程要忽略和處理一些接收到的(9php.com)信號(hào),如子進(jìn)程結(jié)束時(shí)會(huì)發(fā)送SIGCHLD信號(hào)組父進(jìn)程,有些daemon進(jìn)程通過(guò)SIGHUP信號(hào)來(lái)重啟。
              signal(SIG_IGN,SIGCHLD); /* child terminate signal */
            上面的(9php.com)代碼將忽略SIGCHLD信號(hào)。
              void Signal_Handler(sig) /* signal handler function */
            ? ? int sig;
            ? ? {
            ? ?? ???switch(sig){
            ? ?? ?? ?? ?case SIGHUP:
            ? ?? ?? ?? ?? ? /* rehash the server */
            ? ?? ?? ?? ?? ? break;? ?? ???
            ? ?? ?? ?? ?case SIGTERM:
            ? ?? ?? ?? ?? ? /* finalize the server */
            ? ?? ?? ?? ?? ? exit(0)
            ? ?? ?? ?? ?? ? break;? ?? ???
            ? ?? ???}? ?
            ? ? }

            ? ? signal(SIGHUP,Signal_Handler); /* hangup signal */
            ? ? signal(SIGTERM,Signal_Handler); /* software termination signal from kill */
            ??建立一個(gè)信號(hào)處理函數(shù),并與信號(hào)關(guān)聯(lián)。
            8,日志處理
            ??運(yùn)行程序有一些重要的(9php.com)信息需要記日志,有如下幾種方法記錄日志:
            ??重定向輸出到標(biāo)準(zhǔn)I/O,這種方式將日志直接輸出到終端(顯示器),實(shí)際上這個(gè)程序是運(yùn)行在前臺(tái)的(9php.com)。這種方式不適用于daemon進(jìn)程。
            ??寫日志文件,將日志寫入文件。
            ?? void log_message(filename,message)
            ? ? char *filename;
            ? ? char *message;
            ? ? {
            ? ? FILE *logfile;
            ? ?? ???logfile=fopen(filename,"a");
            ? ?? ???if(!logfile) return;
            ? ?? ???fprintf(logfile,"%s\n",message);
            ? ?? ???fclose(logfile);
            ? ? }

            ? ? log_message("conn.log","connection accepted");
            ? ? log_message("error.log","can not open file");
            日志服務(wù):這種方式是將日志送給一個(gè)日志服務(wù),由日志服務(wù)來(lái)記錄日志,并提供查閱,
            UNIX系統(tǒng)帶有SYSLOGD日志服務(wù),可以通過(guò)如下方式將日志寫入SYSLOGD。
              openlog("mydaemon",LOG_PID,LOG_DAEMON)
            ? ? syslog(LOG_INFO, "Connection from host %d", callinghostname);
            ? ? syslog(LOG_ALERT, "Database Error !");
            ? ? closelog();
            就寫這么多了,要變成你自己的(9php.com)東東,還得你自己去研究.希望這篇文章對(duì)初學(xué)者有個(gè)指引.

            Daemon設(shè)計(jì)原則

            Daemon程序設(shè)計(jì)主要原則包括:

            (1)?????? 程序運(yùn)行后調(diào)用fork,并讓父進(jìn)程退出。子進(jìn)程獲得一個(gè)新的進(jìn)程ID,但繼承了父進(jìn)程的進(jìn)程組ID。

            (2)?????? 調(diào)用setsid創(chuàng)建一個(gè)新的session,使自己成為新session和新進(jìn)程組的leader,并使進(jìn)程沒(méi)有控制終端(tty)。

            (3)?????? 設(shè)置文件創(chuàng)建mask為0,避免創(chuàng)建文件時(shí)權(quán)限的影響。

            (4)?????? 關(guān)閉不需要的打開(kāi)文件描述符。因?yàn)镈aemon程序在后臺(tái)執(zhí)行,不需要于終端交互,通常就關(guān)閉STDIN、STDOUT和STDERR。其它根據(jù)實(shí)際情況處理。

            (5)?????? Daemon無(wú)法輸出信息,可以使用SYSLOG或自己的日志系統(tǒng)進(jìn)行日志處理。(可選)

            (6)?????? 編寫管理Daemon的SHELL腳本,使用service對(duì)Daemon進(jìn)行管理和監(jiān)控。(可選)

            Daemon程序框架

            int init_daemon(void)

            {

            ? pid_t pid;

            ? int i;

            ?

            ? /* parent exits , child continues */

            ? if((pid = fork()) < 0)

            ??? return -1;

            ? else if(pid != 0)

            ??? exit(0);

            ?

            ? setsid(); /* become session leader */

            ? for(i=0;i< NOFILE ;++i) /* close STDOUT, STDIN, STDERR, */

            ??? close(i);

            ?

            ? umask(0); /* clear file mode creation mask */

            ? return 0;

            }

            ?

            void sig_term(int signo)

            {

            ? if(signo == SIGTERM)? /* catched signal sent by kill(1) command */

            ? {

            ???? wsio_logit("", "wsiod stopped\n");

            ???? exit(0);

             }

            }

            ?

            /* main program of daemon */

            int main(void)

            {

            if(init_daemon() == -1){

            printf("can't fork self\n");

            exit(0);

            ? }

            ? wsio_logit("", "wsiod started\n");

            ? signal(SIGTERM, sig_term); /* arrange to catch the signal */

            ?

            ? while (1) {

            ??? // Do what you want here

            ??? … …

            ? }

            ? exit(0);

            }

            Daemon日志

            這里使用自己的日志系統(tǒng),當(dāng)然也可以使用SYSLOG。

            #define LOGBUFSZ 256???? /*log buffer size*/

            #define LOGFILE? "/var/log/wsiod.log"? /*log filename*/

            int wsio_logit(char * func, char *msg, ...)

            {

            ??????? va_list args;

            ??????? char prtbuf[LOGBUFSZ];

            ??????? int save_errno;

            ??????? struct tm *tm;

            ??????? time_t current_time;

            ??????? int fd_log;

            ?

            ??????? save_errno = errno;

            ??????? va_start (args, msg);

            ??????? (void) time (&current_time);??????????? /* Get current time */

            ??????? tm = localtime (&current_time);

            ??????? sprintf (prtbuf, "%02d/%02d %02d:%02d:%02d %s ", tm->tm_mon+1,

            ??????????????????? tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, func);

            ??????? vsprintf (prtbuf+strlen(prtbuf), msg, args);

            ??????? va_end (args);

            ??????? fd_log = open (LOGFILE, O_WRONLY | O_CREAT | O_APPEND, 0664);

            ??????? write (fd_log, prtbuf, strlen(prtbuf));

            ??????? close (fd_log);

            ??????? errno = save_errno;

            ??????? return 0;

            }

            Daemon管理

            Daemon程序可以使用service工具進(jìn)行管理,包括啟動(dòng)、停止、查看狀態(tài)等,但前題是需要編寫一個(gè)如下的簡(jiǎn)單SHELL腳本。

            # /etc/rc.d/init.d/wsiod

            #!/bin/sh

            #

            # wsiod???????? This shell script takes care of starting and stopping wsiod.

            #

            # chkconfig: 35 65 35

            # description: wsiod is web servce I/O server, which is used to access files on remote hosts.

            ?

            # Source function library.

            . /etc/rc.d/init.d/functions

            ?

            # Source networking configuration.

            . /etc/sysconfig/network

            ?

            # Check that networking is up.

            [ ${NETWORKING} = "no" ] && exit 0

            ?

            RETVAL=0

            prog="wsiod"

            WSIOARGS="-h $HOSTNAME -p 80 -t STANDALONE -k -c -d"

            start() {

            ??????? # Start daemons.

            ??????? echo -n $"Starting $prog: "

            ??????? daemon /usr/local/bin/wsiod ${WSIOARGS}

            ??????? RETVAL=$?

            ??????? echo

            ??????? [ $RETVAL -eq 0 ] && touch /var/lock/subsys/wsiod

            ??????? return $RETVAL

            }

            stop() {

            ??????? # Stop daemons.

            ??????? echo -n $"Shutting down $prog: "

            ??????? killproc wsiod

            ??????? RETVAL=$?

            ??????? echo

            ??????? [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/wsiod

            ??????? return $RETVAL

            }

            ?

            # See how we were called.

            case "$1" in

            ? start)

            ??????? start

            ??????? ;;

            ? stop)

            ?????? ?stop

            ??????? ;;

            ? restart|reload)

            ??????? stop

            ??????? start

            ??????? RETVAL=$?

            ??????? ;;

            ? status)

            ??????? status wsiod

            ??????? RETVAL=$?

            ??????? ;;

            ? *)

            ??????? echo $"Usage: $0 {start|stop|restart|status}"

            ??????? exit 1

            esac

            ?

            exit $RETVAL

            ?

            OK,到這兒為止,一個(gè)完整的Linux Daemon程序就完成了。

            国产成人精品久久免费动漫 | 久久99精品久久久久久| 久久亚洲私人国产精品| 久久91精品国产91久久麻豆| 99久久精品免费看国产一区二区三区| 久久国产成人亚洲精品影院| 亚洲?V乱码久久精品蜜桃 | 综合久久精品色| 亚洲午夜久久影院| 久久人做人爽一区二区三区| 人人狠狠综合久久亚洲88| 国产精品一区二区久久精品涩爱| 久久男人Av资源网站无码软件 | 久久er国产精品免费观看2| 蜜臀久久99精品久久久久久| 国产日韩久久久精品影院首页| 99久久久精品免费观看国产| 亚洲AV日韩精品久久久久久| 久久久久亚洲AV片无码下载蜜桃| 18岁日韩内射颜射午夜久久成人| 久久久久av无码免费网| 精品久久久久久无码中文野结衣| 久久久久99精品成人片试看| 伊人色综合久久天天人守人婷| 久久国产三级无码一区二区| 亚洲嫩草影院久久精品| 久久久无码一区二区三区| 精品国产乱码久久久久久呢| 亚洲国产成人久久综合区| 久久免费大片| 亚洲欧美精品一区久久中文字幕| 精品一久久香蕉国产线看播放 | 午夜视频久久久久一区| 久久久久香蕉视频| 亚洲国产成人精品久久久国产成人一区二区三区综 | 国产成人久久精品麻豆一区| 国产精品久久久久影院色| 人妻丰满AV无码久久不卡| 欧美牲交A欧牲交aⅴ久久 | 精品久久久久久国产91| 久久精品国产91久久麻豆自制|