守护进程
来源:互联网 发布:淘宝 知乎 姨 编辑:程序博客网 时间:2024/05/01 12:50
一、常用的守护进程简单介绍:
- Keventd:为在内核中运行计划执行的函数提供进程上下文。
- kapmd:高级电源管理。
- kswapd:页面调出。(将脏页面以低速写到磁盘上从而使这些页面在需要时仍可回收使用)
- bdflush:将脏缓冲区从缓存池中冲洗到磁盘上。
- kupdated:每个一定时间间隔,这个守护进程将脏页面冲洗到磁盘上。
- portmap:端口映射提供将RPC程序号映射为网络端口号。
- syslogd:把系统消息记入日志。
- inetd:监听网络接口,以便取得来自网络的对各种网络服务进程的请求。
- cron:在指定的日期和时间执行指定的命令。
二、守护进程的编程规则
1. 重设文件创建掩模
进程从创建它的父进程那里继承了文件创建掩模。它可能修改守护进程所创建的文件的存取位。为防止这一点,将文件创建掩模清除:umask(0);
2.在后头运行
调用fork,然后使父进程终止。这样做的目的是:第一,如果该守护进程是作为一条简单shell命令启动的,那么父进程终止使得shell认为这条命令已经执行完毕,那么子进程就自动在后台运行了。第二,子进程继承了父进程的进程组ID,但具有一个新的进程ID,这就保证了进程不是一个进程组的组长进程。这是接下去调用setsid的必要条件。
3.脱离控制终端,登录会话和进程组
调用setsid以创建一个新会话。使调用进程:(a)成为新会话的首进程,(b)成为一个新进程组的组长进程,(c)没有控制终端。
有必要先介绍一下Linux中的进程与控制终端,登录会话和进程组之间的关系:进程属于一个进程组,进程组号(GID)就是进程组长的进程号(PID)。登录会话可以包含多个进程组。这些进程组共享一个控制终端。这个控制终端通常是创建进程的登录终端。
控制终端,登录会话和进程组通常是从父进程继承下来的。我们的目的就是要摆脱它们,使之不受它们的影响。方法是在第2点的基础上,调用setsid()使进程成为会话组长。
说明:当进程是会话组长时setsid()调用失败。但第二点已经保证进程不是会话组长。setsid() 调用成功后,进程成为新的会话组长和新的进程组长,并与原来的登录会话和进程组脱离。由于会话过程对控制终端的独占性,进程同时与控制终端脱离。
4. 禁止进程重新打开控制终端
现在,进程已经成为无终端的会话组长。但它可以重新申请打开一个控制终端。可以通过使进程不再成为会话组长来禁止进程重新打开控制终端:
if(pid=fork())
exit(0);//结束第一子进程,第二子进程继续(第二子进程不再是会话组长)
5. 改变当前工作目录
进程活动时,其工作目录所在的文件系统不能卸下。一般需要将工作目录改变到根目录。
chdir("/");
6.关闭打开的文件描述符
进程从创建它的父进程那里继承了打开的文件描述符。如不关闭,将会浪费系统资源,造成进程所在的文件系统无法卸下以及引起无法预料的错误。
7.将文件描述符0、1、2重定向到/dev/null
#include <stdlib.h>#include <stdio.h>#include <syslog.h>#include <signal.h>#include <fcntl.h>#include <sys/resource.h>#include <errno.h>#include <sys/stat.h>#include <string.h>#define LOCKDIR "/var/run/"#define LOCKMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)int daemonize(const char *cmd);int already_running(const char *cmd);int lockfile(int);int main(int argc ,char **argv){ FILE *f; time_t t; if(daemonize(argv[0]) < 0){ printf("daemonize error.\n"); exit(1); } /* make sure only one cope of the daemon is running */ if(already_running(argv[0])){ syslog(LOG_ERR,"daemon already running"); exit(1); } while(1){ sleep(60); if((f = fopen("test.log","a")) >= 0){ t=time(0); fprintf(f,"I'm here at %s\n",asctime(localtime(&t))); } fclose(f); } return 0;}int daemonize(const char *cmd){ int i,fd0,fd1,fd2; pid_t pid; struct rlimit rl; struct sigaction sa; /* clear file creation mask */ umask(0); /* get maximum number of file descriptors */ if(getrlimit(RLIMIT_NOFILE, &rl) < 0 ) exit(1); /* become a session leader to lose controlling tty */ if((pid = fork()) < 0) return -1; else if(pid != 0 ) exit(0); setsid(); /*ensure future opens won't allocate controlling TTYs */ sa.sa_handler=SIG_IGN; sigemptyset(&sa.sa_mask); sa.sa_flags=0; if(sigaction(SIGHUP,&sa,NULL) < 0 ) return -1; if((pid = fork()) < 0 ) return -1; else if(pid != 0 ) exit(0); /* change the current working directory to the root */ if(chdir("/") < 0 ) return -1; /* close all open file descriptors */ if(rl.rlim_max == RLIM_INFINITY) rl.rlim_max=1024; for(i=0; i < rl.rlim_max; i++) close(i); /* attach file descriptors 0,1,2 to /dev/null */ fd0=open("/dev/null",O_RDONLY); fd1=open("/dev/null",O_RDWR); fd2=open("/dev/null",O_RDWR); /* initialize the log file */ openlog(cmd, LOG_CONS, LOG_DAEMON); if(fd0 != 0 ||fd1 != 1 ||fd2 != 2){ syslog(LOG_ERR,"unexpected file descriptors %d %d %d",fd0,fd1,fd2); exit(1); } return 0;}int lockfile(int fd){ struct flock fl; fl.l_type=F_WRLCK; fl.l_start=0; fl.l_whence=SEEK_SET; fl.l_len=0; return (fcntl(fd,F_SETLK,&fl));}int already_running(const char *cmd){ int fd; char buf[16]; char lfile[32]; strcat(lfile,LOCKDIR); strcat(lfile,cmd); strcat(lfile,".pid"); if((fd = open(lfile, O_RDWR|O_CREAT, LOCKMODE)) < 0 ){ syslog(LOG_ERR, "can't open %s: %m",lfile); exit(1); } if(lockfile(fd) < 0 ){ if(errno == EACCES || errno == EAGAIN){ close(fd); return 1; } syslog(LOG_ERR, "can't lock %s: %m",lfile); exit(1); } ftruncate(fd,0); sprintf(buf, "%ld",(long)getpid()); write(fd,buf,strlen(buf)+1); return 0;}
- 守护进程守护自身
- 守护线程、守护进程
- 守护进程
- 守护进程
- 守护进程
- 守护进程
- 进程守护
- 守护进程
- 守护进程
- 守护进程
- 守护进程
- 守护进程
- 守护进程
- 守护进程
- 守护进程
- 守护进程
- 守护进程
- 守护进程
- 大话存储系列16——VFS 文件系统
- vs2010 sp1 创建silverlight 时,提示我 “在创建silverlight项目之前,您需要安装最新的silverlight Developer运行时
- C++笔记4
- eclipse 汉化 (无版本之忧)
- IOS CoreText.framework --- 段落样子CTParagraphStyle
- 守护进程
- poj 1716 -- Integer Intervals ( 差分约束 )
- Ubuntu 12.10击败Windows 8的十个理由
- tomcat的maxThreads、acceptCount(最大线程数、最大排队数)
- 哪些App适合用HTML5开发?
- Android上常见度量单位【xdpi、hdpi、mdpi、ldpi】解读
- 高性能HTTP加速器Varnish搭建、配置及优化
- Google 精神之死:别了,曾经的理想和信念
- 网管的三个重要服务AAA、NTP和SYSLOG