• <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),開心的工作
            簡單、開放、平等的公司文化;尊重個(gè)性、自由與個(gè)人價(jià)值;
            posts - 1098, comments - 335, trackbacks - 0, articles - 1
              C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

            如何編寫UNIX DAEMON程序

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

            unix 進(jìn)程可以運(yùn)行在前臺或是后臺,運(yùn)行在前臺的(9php.com)程序通過終端與用戶進(jìn)行交互,而后以進(jìn)程是單獨(dú)運(yùn)行的(9php.com),用戶可以查看它的(9php.com)狀態(tài),但不清楚它具體在做什么。我們將運(yùn)行在后臺的(9php.com)程序叫做"daemon"程序。如常見的(9php.com)httpd,nfsd,sshd都屬于"daemon"程序,要寫這樣的(9php.com)程序,你可能要考慮如下的(9php.com)一些處理。
            1,后臺運(yùn)行處理
            使用FORK()調(diào)用創(chuàng)建一個(gè)子進(jìn)程,然后讓父進(jìn)程退出。這樣子進(jìn)程就與父進(jìn)程分離了并運(yùn)行在后臺。
            ? ? 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)程將會接收關(guān)聯(lián)終端的(9php.com)信號。為了防止daemon程序從創(chuàng)建它的(9php.com)進(jìn)程接收信號,必需去除與控制終端的(9php.com)關(guān)聯(lián)。
            在UNIX系統(tǒng)中,進(jìn)程運(yùn)行在一個(gè)進(jìn)程組,子進(jìn)程會從父進(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)文件描述符號和標(biāo)準(zhǔn)I/O處理
            子進(jìn)程會繼承父進(jìn)程打開的(9php.com)文件描述符,這樣會導(dǎo)致文件描述符資源的(9php.com)浪費(fèi),所以應(yīng)該關(guān)閉所有繼承過來的(9php.com)文件描述符。
            ? ? for (i=getdtablesize();i>=0;--i) close(i); /* close all descriptors */
            對于stdin,stdout,stderr,將它們重定向到/dev/null。
            ? ? i=open("/dev/null",O_RDWR); /* open stdin */
            ? ? dup(i); /* stdout */
            ? ? dup(i); /* stderr */
            由于關(guān)閉了所有文件描述符,上面的(9php.com)操作會從0開始順序產(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è)文件,并對其加鎖,在進(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,信號處理
            對于daemon進(jìn)程要忽略和處理一些接收到的(9php.com)信號,如子進(jìn)程結(jié)束時(shí)會發(fā)送SIGCHLD信號組父進(jìn)程,有些daemon進(jìn)程通過SIGHUP信號來重啟。
              signal(SIG_IGN,SIGCHLD); /* child terminate signal */
            上面的(9php.com)代碼將忽略SIGCHLD信號。
              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è)信號處理函數(shù),并與信號關(guān)聯(lián)。
            8,日志處理
            ??運(yùn)行程序有一些重要的(9php.com)信息需要記日志,有如下幾種方法記錄日志:
            ??重定向輸出到標(biāo)準(zhǔn)I/O,這種方式將日志直接輸出到終端(顯示器),實(shí)際上這個(gè)程序是運(yùn)行在前臺的(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ù)來記錄日志,并提供查閱,
            UNIX系統(tǒng)帶有SYSLOGD日志服務(wù),可以通過如下方式將日志寫入SYSLOGD。
              openlog("mydaemon",LOG_PID,LOG_DAEMON)
            ? ? syslog(LOG_INFO, "Connection from host %d", callinghostname);
            ? ? syslog(LOG_ALERT, "Database Error !");
            ? ? closelog();
            就寫這么多了,要變成你自己的(9php.com)東東,還得你自己去研究.希望這篇文章對初學(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)程沒有控制終端(tty)。

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

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

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

            (6)?????? 編寫管理Daemon的SHELL腳本,使用service對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è)如下的簡單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程序就完成了。

            国产日韩久久免费影院 | 久久久WWW免费人成精品| 久久99热这里只有精品国产| 久久99热这里只频精品6| 亚洲精品乱码久久久久久不卡| 无码精品久久一区二区三区| 久久久人妻精品无码一区| 久久久久久免费视频| 无码国内精品久久综合88| 日韩人妻无码精品久久免费一| 少妇内射兰兰久久| 久久精品无码一区二区三区| 久久91精品久久91综合| 国产精品伦理久久久久久| 国产免费久久久久久无码| 国内精品伊人久久久久妇| 久久久精品人妻一区二区三区蜜桃 | 亚洲国产美女精品久久久久∴| 久久久久人妻精品一区二区三区| 亚洲精品美女久久久久99小说| 久久99久久99精品免视看动漫| 精品午夜久久福利大片| 精品久久久久久久国产潘金莲| 久久精品国产99国产电影网 | 国产精品免费看久久久| 国内精品免费久久影院| 99久久精品免费看国产一区二区三区 | 久久久一本精品99久久精品88| 日产久久强奸免费的看| 国产午夜精品久久久久九九电影| 久久发布国产伦子伦精品| 午夜精品久久久久久中宇| 国内精品伊人久久久久妇| 日产精品久久久久久久| 亚洲国产成人精品91久久久 | 久久夜色精品国产噜噜亚洲a| 久久99精品久久久久久水蜜桃| 久久精品国内一区二区三区| 久久综合狠狠色综合伊人| 亚洲国产成人久久综合一| 国产一区二区精品久久|