首页 »Unix/FreeBsd » unix守护进程:编写Linux/Unix守护进程 »正文unix守护进程:编写Linux/Unix守护进程来源: 发布时间:星期四, 2009年2月12日 浏览:47次 评论:0
守护进程在Linux/Unix系统中有着广泛应用有时开发人员也想把自己变成守护进程在创建个守护进程时候要接触到子进程、进程组、会晤期、信号机制、文件、目录和控制终端等多个概念因此守护进程还是比较复杂在这里详细地讨论Linux/Unix守护进程编写整理总结出 8条经验并给出应用范例 编程要点 1.屏蔽些有关控制终端操作信号防止在守护进程没有正常运转起来时控制终端受到干扰退出或挂起举例如下: signal(SIGTTOU,SIG_IGN); signal(SIGTTIN,SIG_IGN); signal(SIGTSTP,SIG_IGN); signal(SIGHUP ,SIG_IGN); 所有信号都有自己名字这些名字都以“SIG”开头只是后面有所区别开发人员可以通过这些名字了解到系统中发生了什么事当信号出现时开发人员可以要求系统进行以下 3种操作: ◆ 忽略信号大多数信号都是采取这种方式进行处理这里就采用了这种使用方法但值得注意是对SIGKILL和SIGSTOP信号不能做忽略处理 ◆ 捕捉信号最常见情况就是如果捕捉到SIGCHID信号则表示子进程已经终止然后可在此信号捕捉中waitpid取得该子进程进程ID和它终止状态另外如果进程创建了临时文件那么就要为进程终止信号SIGTERM编写个信号捕捉来清除这些临时文件 ◆ 执行系统默认动作对绝大多数信号而言系统默认动作都是终止该进程 对这些有关终端信号般采用忽略处理从而保障了终端免受干扰 这类信号分别是SIGTTOU(表示后台进程写控制终端)、SIGTTIN(表示后台进程读控制终端)、SIGTSTP(表示终端挂起)和SIGHUP(进程组长退出时向所有会议成员发出) 2.将进入后台执行由于守护进程最终脱离控制终端到后台去运行思路方法是在进程中fork使父进程终止让Daemon在子进程中后台执行这就是常说“脱壳”子进程继续fork定义如下: # # pid_t fork(void); 该是Linux/Unix编程中非常重要它被次但返回两次这两次返回区别是子进程返回值为“0”而父进程返回值为子进程ID如果出错则返回“-1” 3.脱离控制终端、登录会话和进程组开发人员如果要摆脱它们不受它们影响般使用 sid 设置新会话领头进程并和原来登录会话和进程组脱离这只是其中种思路方法也有如下处理办法: ((fd = open("/dev/tty",O_RDWR)) >= 0) { ioctl(fd,TIOCNOTTY,NULL); close(fd); } 其中/dev/tty是个流设备也是终端映射close将终端关闭 4.禁止进程重新打开控制终端进程已经成为无终端会话组长但它可以重新申请打开个控制终端开发人员可以通过不再让进程成为会话组长方式来禁止进程重新打开控制终端需要再次fork 上面代码表示结束第子进程第 2子进程继续(第 2子进程不再是会话组长) 5. 关闭打开文件描述符并重定向标准输入、标准输出和标准输出文件描述符进程从创建它父进程那里继承了打开文件描述符如果不关闭将会浪费系统资源引起无法预料关闭 3者代码如下: for (fd = 0, fdtablesize = getdtablesize; fd < fdtablesize; fd) close(fd); 但标准输入、标准输出和标准输出重定向是可选也许有想保留标准输入(0)、标准输出(1)和标准输出(2)那么循环应绕过这 3者代码如下: for (fd =3, fdtablesize = getdtablesize; fd < fdtablesize; fd) close(fd); 有有些特殊需求还需要将这 3者重新定向举例如下: error=open("/tmp/error",O_WRONLY|O_CREAT, 0600); dup2(error,2); close(error); in=open("/tmp/in",O_RDONLY|O_CREAT,0600); (dup2(in,0)-1) perror("in"); close(in); out=open("/tmp/out",O_WRONLY|O_CREAT,0600); (dup2(out,1)-1) perror("out"); close(out); 6.改变工作目录到根目录或特定目录进程活动时其工作目录所在文件系统不能卸下 般需要将工作目录改变到根目录或特定目录注意用户对此目录需要有读写权防止超级用户卸载设备时系统报告设备忙 7.处理SIGCHLD信号SIGCHLD信号是子进程结束时向内核发送信号 如果父进程不等待子进程结束子进程将成为僵尸进程(zombie)从而占用系统资源因此需要对SIGCHLD信号做出处理回收僵尸进程资源避免造成不必要资源浪费可以用如下语句: signal(SIGCHLD,(void *)reap_status); 捕捉信号SIGCHLD用下面进行处理: void reap_status { pid; union wait status; while ((pid = wait3(&status,WNOHANG,NULL)) > 0) …… } 8.在Linux/Unix下有个syslogd守护进程向用户提供了syslog系统任何都可以通过syslog记录事件 由于syslog非常好用和易配置所以很多都使用syslog来发送它们记录信息般守护进程也使用syslog向系统输出信息syslog有 3个般只需要用syslog(...)openlog/closelog可有可无syslog在shslog.h定义如下: # void syslog( priority,char *format,...); 其中参数priority指明了进程要写入信息等级和用途第 2个参数是个格式串指定了记录输出格式在这个串最后需要指定个%m对应errno码 应用范例 下面给出Linux下编程守护进程应用范例在UNIX中区别版本实现细节可能不致但其实现原则是和Linux致 # # # ( argc,char **argv) { time_t now; childpid,fd,fdtablesize; error,in,out; /* 忽略终端 I/O信号,STOP信号 */ signal(SIGTTOU,SIG_IGN); signal(SIGTTIN,SIG_IGN); signal(SIGTSTP,SIG_IGN); signal(SIGHUP ,SIG_IGN); /* 父进程退出,进入后台运行 */ (fork!=0) exit(1); (sid<0)exit(1);/* 创建个新会议组 */ /* 子进程退出,孙进程没有控制终端了 */ (fork!=0) exit(1); (chdir("/tmp")-1)exit(1); /* 关闭打开文件描述符,包括标准输入、标准输出和标准输出 */ for (fd = 0, fdtablesize = getdtablesize; fd < fdtablesize; fd) close(fd); umask(0);/*重设文件创建掩模 */ signal(SIGCHLD,SIG_IGN);/* 忽略SIGCHLD信号 */ /*打开log系统*/ syslog(LOG_USER|LOG_INFO,"守护进程测试!\n"); while(1) { time(&now); syslog(LOG_USER|LOG_INFO,"当前时间:\t%s\t\t\n",ctime(&now)); sleep(6); } } 此在Turbo Linux 4.0下编译通过这个比较简单但基本体现了守护进程编程要点读者针对实际应用中区别需要还可以做相应调整 0
相关文章
读者评论发表评论 |