首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 操作系统 > UNIXLINUX >

也谈编写UNIX上的daemon程序

2012-08-28 
也谈编写UNIX下的daemon程序【作者】冀卫东一、引言《微电脑世界》1997年第5期上刊登了一篇关于如何编写Unix da

也谈编写UNIX下的daemon程序

【作者】冀卫东     一、引言     《微电脑世界》1997年第5期上刊登了一篇关于如何编写Unix daemon程序的文章,介绍了编写daemon程序的几个编程准则,主要包括以下几点:     (1)使daemon进程不受后台作业I/O影响,让daemon进程忽略SIGTTOU、SIGTTIN、SIGTST P信号;     (2)将daemon进程与它的原始进程组和控制终端脱离,采用setpgrp(),setsid()函数调用 ;     (3)关闭打开文件;     (4)将状态写入一磁盘文件;     (5)将当前目录改为根目录。 随着网络和客户机/服务器方式的普及,服务器上的daemon进程越来越多,性能要求也越来越高,除了以上几点外,还有一些应注意的事项,如不注意会降低daemon进程的性能甚至导致死机。这里对编写daemon程序作一些补充,供大家参考。     二、daemon编程应注意的几个问题     1.应使daemon产生的子进程运行结束后消失     daemon进程常常要产生子进程来响应客户机发来的请求,但这些子进程在运行完后并不消失,而是变为僵尸进程(zombie process)。如频繁响应客户机发来的请求,会使僵尸进程过多而导致速度变慢甚至死机。因为子进程运行结束后并不消失,而是等待daemon进程运行终止后消失。解决办法是让daemon进程忽略SIGCHLD信号,这样子进程运行完后会自动消失。     函数调用为SIGNAL(SIGCHLD,SIG-IGN)     2.daemon终止前应进行善后处理     daemon进程在起动后通常要做初使化工作,如改变设置,重新设定参数,打开文件。daem on进程起动后,不可能无休止地运行下去,一般需通过信号使其终止。终止前,应注意恢复原设定,关闭文件。可采用以下方式:     workend()     {     close files;/*关闭文件*/     restore old parameters;/*恢复原参数*/     ...... /*其它参数恢复*/     }     function()     {     .........     SIGNAL(SIGTERM,workend);     SIGNAL(SIGQUIT,workend);     ........     }     同时,中止daemon进程时,应使用SIGTERM(15),SIGQUIT(3)信号,避免使用SIGKILL(9),因其不可被捕捉,不会执行结束函数。     3.定时强制中断     daemon进程常要产生子进程来响应客户机发来的请求,有时处理客户请求的函数可能不太完善,会无休止的运行下去(如死循环)而不会返回,这样会使发出请求的客户进程无限期等待,造成客户机死机。解决办法是在客户机或服务器上增加超时检测机制,首先设定最大处里时间,当超过这一时间即终止运行,返回错误码。可采用以下方式:     #define MaxWaitTime 10 /*设定最大时间为10秒*/     jmp-buf jmpenv;     int (*sign)();     timeout()     {     longjmp(jmpenv,1);     };     在子进程前部,设:     if (setjmp(jmpenv)!=0)     {     alarm(0);/* 恢复原ALARM()参数 */     signal(SIGALRM,sign);/* 恢复原SIGNAL()参数 */     ...............     return(-1);     };     sign=signal(SIGALRM,timeout);/*设新信号函数*/     alarm(MaxWaitTime); /*设最大等待时间*/     process()......;/*程序处理*/     alarm(0);/* 恢复原ALARM()参数 */     signal(SIGALRM,sign);/* 恢复原SIGNAL()参数 */     ......     4.防止daemon进程重复起动     由于daemon进程一般在后台运行,如不注意极易造成重复起动,最好在程序起动时能自行检测,发现后台程序已运行则自行终止。     可编一SHELL程序来判断,程序名定为:TestDaemonExist:     DaemonNum=`ps -e|grep "Daemon-name"|wc -l`     if [ $DaemonNum -ge 2 ]     then     echo 1  #如daemon进程已起动,则返回1     else     echo 0  #如daemon进程未起动,则返回0     fi     在程序前部,增加一个判断     #include <glib.h>     gchar*output;     g_spawn_command_line_sync("TestDaemonExist Daemon-name", &output, NULL, NILL, NULL);     if (atoi (output))     // if (system("TestDaemonExist Daemon-name")!=0)     {     printf("daemon进程已起动!!!");     exit(0);     };     5.客户机与服务器间的通讯应采用字符串(字节流)方式     客户机与服务器间会频繁的有数据交换,这些数据包括各种数据类型,如整型、单精度、双精度、字符等类型,由于不同的机器间编译方式不同,因此各数据长度不同(如某些机器以 8字节对齐,不满8位则空位补齐,这样一个整数本来占2个字节,现在则占8个字节;而有的机器占2个字节),造成偏移量或结构大小错误,进而数值传错,不同的机器间交换尤其如此。解决办法是将参数统一改为字符串(字节流)方式传输,不同的项间增加分隔符,或固定长度,使用时再转变为各种数据类型,这样才能保正数据交换正确。     6.daemon进程同子进程间协调运行     daemon进程产生子进程后,子进程继承父进程的参量,如文件描述符,变量值等。这样,一个文件在父进程中被打开,在子进程中也被打开。如父子进程都向文件中写数据,则文件以最后关闭的进程写入的数据为准,其它进程写入的均无效。(如同多个用户用VI编辑同一个文件 ,结果以最后存盘的为准一样)。daemon进程和子进程应避免这种情况发生,一个进程打开一个文件时,其它进程应将其关闭。父子进程的参数传递可采用管道,共享存储区、消息队列等方式,还可通过信号量来协调运行。     三、daemon本身程序的框架     下面的程序仅仅是一个框架,将它编译链接成运行程序,结合1997年第5期上的daemon程序,用以帮助daemon运行,即可实现一个完整的daemon程序。     #define MaxWaitTime 10 /*设定最大时间为10秒*/     jmp-buf jmpenv;     int (*sign)();     timeout()     {     longjmp(jmpenv,1);     };     workend()     {     close files;/*关闭文件*/     restore old parameters;/*恢复原参数*/     ...... /*其它参数恢复*/     }     main()/*daemon程序*/     {     if (system("TestDaemonExist Daemon-name")!=0)     {     printf("daemon进程已起动!!!");     exit(0);     };     signal(SIGCHLD ,sign);/* 使子进程运行完后消失 */     signal(SIGTERM,workend);/*终止前做恢复*/     signal(SIGQUIT,workend);/*终止前做恢复*/     ...............     if (fork()=0)/*如果需产生子进程处理*/     {     If (setjmp(jmpenv)!=0)     {     alarm(0);/* 恢复原ALARM()参数 */     signal(SIGALRM,sign);/* 恢复原SIGNAL()参数 */     ...............     return(-1);/*返回错误码*/     };     sign=signal(SIGALRM,timeout);/*设新信号函数*/     alarm(MaxWaitTime); /*设最大等待时间*/     process()......;/*程序处理*/     alarm(0);/* 恢复原ALARM()参数 */     signal(SIGALRM,sign);/* 恢复原SIGNAL()参数 */     sign=signal(SIGALRM,timeout);/*设新信号函数*/     alarm(MaxWaitTime); /*设最大等待时间*/     process()......;/*程序处理*/     alarm(0);/* 恢复原ALARM()参数 */     signal(SIGALRM,sign);/* 恢复原SIGNAL()参数 */     ......     }     }     SHELL程序名定为:TestDaemonExist:     DaemonNum=`ps -e|grep $1|wc -l`     if [ $DaemonNum -ge 2 ]     then     exit(1) #如daemon进程已起动,则返回1     else     exit(0) #如daemon进程未起动,则返回0     fi     作为服务器程序,会遇到各种情况。为了能更好地运行,减少错误,应尽可能考虑完全。笔者用以上程序架构写了一些daemon程序,运行效果良好。     (作者地址:中国银行山西省分行信息科技处,030001)

热点排行