博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
探究守护进程及其错误日志处理
阅读量:5327 次
发布时间:2019-06-14

本文共 2987 字,大约阅读时间需要 9 分钟。

守护进程也是通常所说的deamon进程,他是linux中的后台服务进程。它是一个生存期较长的进程,通常独立于控制终端并且周期性的执行某种任务,或者等待处理某些发生的事件

编写守护进程的步骤:

1.创建子进程,父进程退出。

这儿有一个问题,由于父进程先于子进程退出,会造成子进程没有父进程,从而变成一个孤儿进程,在linux中,每当系统发现一个孤儿进程,就会自动由1号进程(init进程)收养,这样原来的子进程就变成init进程的子进程了

其实现代码如下:

pid=fork();

if(pid>0)

{

exit(0);//父进程退出

}

2.在子进程中创建新会话

这儿有一个进程组与会话期的概念

进程组:一个或多个进程的集合,进程组由进程组id来唯一标识

会话期:会话期是一个或多个进程组的集合,会话期的第一个进程称为会话组长

函数setsid()用于创建一个新的会话,并担任会话组组长,其功能如下

1.让进程摆脱原会话的控制

2.让进程摆脱原进程组的控制

3.让进程拜托原控制终端的控制

pid_t setsid(void)

成功返回改进程组id,失败返回-1;

3.改变当当前工作目录chdir();

由于使用fork创建的子进程继承了父进程的当前工作目录,由于在进程运行过程中,当前目录所在的文件系统是不能卸载的,这对以后使用造成了诸多麻烦,通常的做法是让“/”作为当前守护进程的当前工作目录

4.重设文件权限掩码umask(0)

把文件权限设置为0,可以增强该守护进程的灵活性

5.关闭文件描述符

同文件掩码一样,用fork函数新建的子进程会从父进程那里继承一些打开的文件,这些被打开的文件可能永远不会被守护进程访问,但一样占用资源,而且还可能导致所在的文件系统无法卸载

int num;

num=getdtablesize();//获取当前进程文件描述符大小

for(int i=0;i<num;i++)

{

close(i);

}

实例如下:

void deamon_mode(FILE *fp)

{
  pid_t pid;

  pid = fork();

  if(pid < 0){
    perror("Fail to fork");
    exit(EXIT_FAILURE);
  }

  if(pid > 0){

    exit(EXIT_SUCCESS);
  }

  //创建新会话

  if(setsid() < 0){
    perror("Fail to fork");
    exit(EXIT_FAILURE);
  }

//重设文件掩码

umask(0);
//改变进程的工作目录
chdir("/");
//关闭不需要的文件描述符
close(0);
close(1);
close(2);
//重定向
dup2(fp->_fileno,0);
dup2(fp->_fileno,1);
dup2(fp->_fileno,2);

return;

}

//a.out 0(非守护进程) log.txt

//a..out 1(守护进程 ) log.txt
int main(int argc, const char *argv[])
{
  int fd;
  FILE *log_fp;
  int mode;

  if(argc < 3){

    fprintf(stderr,"Usage : %s < mode > <log file> !\n",argv[0]);
    exit(EXIT_FAILURE);
  }

  mode = atoi(argv[1]);

  if(mode){
    log_fp = fopen(argv[2],"a");
    if(log_fp == NULL){
    fprintf(stderr,"Fail to open %s : %s!\n",argv[2],strerror(errno));
    exit(EXIT_FAILURE);
  }
  deamon_mode(log_fp);
}else{
  log_fp = stderr;
}

fd = open("test",O_WRONLY | O_TRUNC | O_CREAT,0666);

if(fd < 0){
  fprintf(log_fp,"Fail to open %s : %s!\n","test",strerror(errno));
  exit(EXIT_FAILURE);
}
  fprintf(log_fp,"open success!\n");
  fflush(log_fp);

  while(1)

  ;

  return 0;

}

以上主要实现一个打印日志的一个功能,如果是守护进程则,通过守护进程打印日志到log.txt,否则非守护进程,打印到屏幕

可能这儿有一个重定向dup2

 

首先看看man手册

 
dup 和 dup2 都可以用来复制一个现存的文件描述符。经常用来重新定向进程的 STDIN, STDOUT, STDERR。
int dup ( int filedes ) ; 函数返回一个新的描述符,这个新的描述符是传给它的描述符的拷贝,若出错则返回 -1。由dup返回的新文件描述符一定是当前可用文件描述符中的最小数值。这函数返回的新文件描述符与参数 filedes 共享同一个文件数据结构。

 

int dup2( int filedes, int filedes2 ) 同样,函数返回一个新的文件描述符,若出错则返回 -1。与 dup 不同的是,dup2 可以用 filedes2 参数指定新描述符的数值。如果 filedes2 已经打开,则先将其关闭。如若 filedes 等于 filedes2 , 则 dup2 返回 filedes2 , 而不关闭它。同样,返回的新文件描述符与参数 filedes 共享同一个文件数据结构。
 

int main(int argc, const char *argv[])

{
  FILE *fp;

 

  fp = fopen(argv[1],"a");

 

  close(0);

  close(1);
  close(2);

 

#if 1

  dup2(fp->_fileno,0);
  dup2(fp->_fileno,1);
  dup2(fp->_fileno,2);
#endif

 

printf("default hello !\n");

fprintf(stdout,"stdout hello !\n");
fprintf(stderr,"stderr hello !\n");
fflush(stdout);
while(1)
;
return 0;
}

编译并运行 a.out log.txt

查看 cat log.txt

可见本应该输出到控制终端的输出到了log.txt

其实对应的日志处理还有几个比较常用:

openlog/syslog/closelog,比较简单,查阅一下便知道!

转载于:https://www.cnblogs.com/bwbfight/p/9282911.html

你可能感兴趣的文章
【题解】 bzoj1597: [Usaco2008 Mar]土地购买 (动态规划+斜率优化)
查看>>
css文本溢出显示省略号
查看>>
git安装和简单配置
查看>>
面向对象:反射,双下方法
查看>>
鼠标悬停提示文本消息最简单的做法
查看>>
课后作业-阅读任务-阅读提问-2
查看>>
面向对象设计中private,public,protected的访问控制原则及静态代码块的初始化顺序...
查看>>
fat32转ntfs ,Win7系统提示对于目标文件系统文件过大解决教程
查看>>
Awesome Adb——一份超全超详细的 ADB 用法大全
查看>>
shell cat 合并文件,合并数据库sql文件
查看>>
Android 将drawable下的图片转换成bitmap、Drawable
查看>>
介绍Win7 win8 上Java环境的配置
查看>>
Linux设置环境变量的方法
查看>>
构建自己的项目管理方案
查看>>
利用pca分析fmri的生理噪声
查看>>
div水平居中且垂直居中
查看>>
epoll使用具体解释(精髓)
查看>>
AndroidArchitecture
查看>>
安装Endnote X6,但Word插件显示的总是Endnote Web"解决办法
查看>>
python全栈 计算机硬件管理 —— 硬件
查看>>