• <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.¢%

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

            如何編寫UNIX DAEMON程序

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

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

            2,進程依賴處理
            每個子進程繼承父進程的(9php.com)控制終端,進程將會接收關聯終端的(9php.com)信號。為了防止daemon程序從創建它的(9php.com)進程接收信號,必需去除與控制終端的(9php.com)關聯。
            在UNIX系統中,進程運行在一個進程組,子進程會從父進程繼承進程組,一個DAEMON進程應該不依賴于進程組的(9php.com)其它進程.
              setsid() /* obtain a new process group */
            這個函數將DAEMON進程放置于一個新的(9php.com)進程組,并去除了與控制終端的(9php.com)關聯。
            3,繼承的(9php.com)文件描述符號和標準I/O處理
            子進程會繼承父進程打開的(9php.com)文件描述符,這樣會導致文件描述符資源的(9php.com)浪費,所以應該關閉所有繼承過來的(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 */
            由于關閉了所有文件描述符,上面的(9php.com)操作會從0開始順序產生文件描述符。

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

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

            6,保持單DAEMON進程處理
            為了保持單daemon進程,防止運行多個daemon進程,有效的(9php.com)方式是建立一個文件,并對其加鎖,在進程退出時進行解鎖。
            ?? lfp=open("exampled.lock",O_RDWR|O_CREAT,0640);
            ? ? if (lfp<0) exit(1); /* can not open */
            ? ? if (lockf(lfp,F_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進程要忽略和處理一些接收到的(9php.com)信號,如子進程結束時會發送SIGCHLD信號組父進程,有些daemon進程通過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 */
            ??建立一個信號處理函數,并與信號關聯。
            8,日志處理
            ??運行程序有一些重要的(9php.com)信息需要記日志,有如下幾種方法記錄日志:
            ??重定向輸出到標準I/O,這種方式將日志直接輸出到終端(顯示器),實際上這個程序是運行在前臺的(9php.com)。這種方式不適用于daemon進程。
            ??寫日志文件,將日志寫入文件。
            ?? 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");
            日志服務:這種方式是將日志送給一個日志服務,由日志服務來記錄日志,并提供查閱,
            UNIX系統帶有SYSLOGD日志服務,可以通過如下方式將日志寫入SYSLOGD。
              openlog("mydaemon",LOG_PID,LOG_DAEMON)
            ? ? syslog(LOG_INFO, "Connection from host %d", callinghostname);
            ? ? syslog(LOG_ALERT, "Database Error !");
            ? ? closelog();
            就寫這么多了,要變成你自己的(9php.com)東東,還得你自己去研究.希望這篇文章對初學者有個指引.

            Daemon設計原則

            Daemon程序設計主要原則包括:

            (1)?????? 程序運行后調用fork,并讓父進程退出。子進程獲得一個新的進程ID,但繼承了父進程的進程組ID。

            (2)?????? 調用setsid創建一個新的session,使自己成為新session和新進程組的leader,并使進程沒有控制終端(tty)。

            (3)?????? 設置文件創建mask為0,避免創建文件時權限的影響。

            (4)?????? 關閉不需要的打開文件描述符。因為Daemon程序在后臺執行,不需要于終端交互,通常就關閉STDIN、STDOUT和STDERR。其它根據實際情況處理。

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

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

            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日志

            這里使用自己的日志系統,當然也可以使用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工具進行管理,包括啟動、停止、查看狀態等,但前題是需要編寫一個如下的簡單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,到這兒為止,一個完整的Linux Daemon程序就完成了。

            久久久www免费人成精品| 囯产精品久久久久久久久蜜桃| 日韩精品久久久肉伦网站 | 欧美久久综合性欧美| 精品久久综合1区2区3区激情| 思思久久99热免费精品6| 国产91色综合久久免费| 日韩精品久久久久久久电影| 国内精品久久国产大陆| 777午夜精品久久av蜜臀| 99久久免费国产精品热| 日韩美女18网站久久精品| 欧美喷潮久久久XXXXx| 久久久久亚洲?V成人无码| 秋霞久久国产精品电影院| 少妇被又大又粗又爽毛片久久黑人| 久久66热人妻偷产精品9| 亚洲AV无码1区2区久久| 亚洲日韩中文无码久久| 午夜视频久久久久一区| 国产AV影片久久久久久| 久久精品国产一区二区电影| 97超级碰碰碰久久久久| 久久99热这里只有精品国产| 久久精品国产精品亚洲艾草网美妙| 国产精品久久久久aaaa| 人妻精品久久无码区| 一本久道久久综合狠狠躁AV| 中文字幕无码久久人妻| 精品多毛少妇人妻AV免费久久| 蜜臀av性久久久久蜜臀aⅴ| 国产A级毛片久久久精品毛片| 国内精品久久久久影院老司| 久久综合久久综合亚洲| 天天影视色香欲综合久久| 久久99精品久久久久久齐齐| 国产精品丝袜久久久久久不卡| 久久精品国产国产精品四凭 | 伊人久久亚洲综合影院| 久久久久噜噜噜亚洲熟女综合| 久久精品国产欧美日韩|