1、守护进程

  守护进程(daemon)是一类在后台运行的特殊进程,用于执行特定的系统任务。很多守护进程在系统引导的时候启动,并且一直运行直到系统关闭。另一些只在需要的时候才启动,完成任务后就自动结束。所有的守护进程都没有控制终端,其终端名设置为问号。

2、编程规则

  1)首先调用umask函数将文件模式创建屏蔽字设置为一个已知值,通常是0;

  umask函数为进程设置文件模式创建屏蔽字,并返回以前的值。umask也是shell命令,功能和umask函数一样。

  1. #include <sys/stat.h>
  2.  
  3. mode_t umask(mode_t mask);

  在进程创建一个新的文件或目录时,如调用open函数创建一个新文件,新文件的实际存取权限是mode与umask按照  mode&~umask运算以后的结果。umask函数用来修改进程的umask。

  首先看一下umask命令的作用:

    首先查看一下当前的umask为022,用vi创建一个umask_3.c,查看该文件的权限为644,修改umask为0,vi创建umask_4.c,查看该文件的权限为666。

     

  umask函数的使用:

    实现函数,首先修改当前进程umask为0.创建fan_test1文件,然后修改umask为006,创建文件fan_test2,输出结果如下图

  1. #include <stdio.h>
  2. #include <sys/stat.h>
  3.  
  4. int main()
  5. {
  6. umask();
  7. if (creat("fan_test1",S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) < )
  8. printf("error creat\n");
  9. umask(S_IROTH|S_IWOTH);
  10. if (creat("fan_test2",S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) < )
  11. printf("error creat\n");
  12. return ;
  13. }

    

  2)调用fork,然后是父进程exit。创建守护进程最关键的一步是调用setsid函数创建一个新的会话(会话是一个或多个进程组的集合),使守护进程成为新会话的首进程,并成为新进程组的组长,失去当前的控制终端,成为一个没有控制终端的进程。而调用函数setsid()之前,要保证当前进程不是进程组的组长,否则该函数返回-1;要保证当前进程不是进程组的组长,就要调用fork,父进程退出;fork创建的子进程和父进程在同一个进程组中,进程组的组长必然是该组的第一个进程,所以子进程不可能是该组的第一个进程,fork之后调用setsid就没有问题了;

  3)调用setsid()函数创建一个新的会话:

       (1) 该进程变成新会话首进程,会话首进程通常是创建该会话的进程,该进程是新会话中的唯一的进程。
       (2) 该进程成为一个新进程组的组长进程,新进程组ID就是调用进程的ID。
       (3) 该进程没有控制终端,如果在调用setsid之前该进程有一个控制终端,那么这种联系将被中断。

  4)将当前的工作目录更改为根目录。如果守护进程所在的目录为一个挂载的文件系统,那么该文件系统就不能被卸载;另外如果守护进程所在的目录不是根目录,启动守护进程之后,当前工作目录所在的文件夹将不能删除;调用函数chdir("/");

  5)关闭打开的文件描述符;子进程有可能从父进程继承了一些打开的文件,这些文件可能守护进程将不再使用,但这些文件描述符依然消耗系统资源,也有可能导致相关的文件系统无法被卸载。

  关闭文件描述符的方法:

  1. 方法1
  2. #include <sys/resource.h>
  3.  
  4. struct rlimit rl;
  5.  
  6. 6 if(getrlimit(RLIMIT_NOFILE, &rl) < )
  7. 7 {
  8. perror("getrlimit(RLIMIT_NOFILE, &rl)");
  9. return -;
  10. 10 }
  11. 11 if(rl.rlim_max == RLIM_INFINITY)
  12. 12 {
  13. 13 rl.rlim_max = ;
  14. 14 }
  15. 15 for(i = ; i < rlim_max; i++)
  16. {
  17. close(i);
  18. }
  19. 方法2
  20. max_fd = sysconf(_SC_OPEN_MAX);
  21. for(i = ; i < max_fd; i++)
  22. {
  23. close(i);
  24. }

  6)守护进程打开/dev/null使其具有文件描述符0、1和2,也就是将0、1、2的文件描述符都指向/dev/null; 

  1. /*attach file descriptions 0,1 and 2 to /dev/null*/
  2. fd0 = open("/dev/null", O_RDWR);
  3. fd1 = dup();
  4. fd2 = dup();

  为什么会有这一步操作,守护进程已经脱离终端了,为什么还要将文件描述符0、1、2重定向到/dev/null呢,并且前面已经有了关闭所有文件描述符的操作,文件描述符已经关闭了,在此处为什么还要再打开,两者不是冲突了么?

  7)再次调用fork,使父进程退出;第一次fork()后的子进程已经成为会话组的组长,有权利再调出一个终端,如果出现此情况,则未达到完全脱离终端的目的,此时再调用fork并退出父进程,使得此时的子进程成为完全的后台进程,独立于任何的终端,在第二次fork之前通常会忽略SIGHUP信号,这是因为会话首进程退出时会给该会话中的前台进程组(当打开控制终端后,就有一个前台进程组)的所有进程发送SIGHUP信号,而信号的默认处理函数通常是进程终止,因此需要对信号进程屏蔽处理

实现一个守护进程:

  1. #include <stdio.h>
  2. #include <sys/stat.h>
  3. #include <signal.h>
  4. #include <sys/resource.h>
  5. #include <unistd.h>
  6. #include <stdlib.h>
  7. void daemonize(void)
  8. {
  9. struct rlimit rl;
  10. pid_t pid;
  11. struct sigaction sa;
  12. int i;
  13. umask();
  14. if (getrlimit(RLIMIT_NOFILE, &rl) < ) {
  15. printf("error getrlimit\n");
  16. exit();
  17. }
  18. if ((pid = fork()) < ) {
  19. printf("error fork\n");
  20. exit();
  21. } else if (pid != ) {
  22. exit();
  23. }
  24. setsid();
  25. sa.sa_handler = SIG_IGN;
  26. sigemptyset(&sa.sa_mask);
  27. sa.sa_flags = ;
  28. if (sigaction(SIGHUP, &sa, NULL) < ) {
  29. printf("error sigaction\n");
  30. exit();
  31. }
  32. if (chdir("/") < ) {
  33. printf("error chdir\n");
  34. exit();
  35. }
  36. if (rl.rlim_max == RLIM_INFINITY)
  37. rl.rlim_max = ;
  38. for (i = ; i < rl.rlim_max; i++)
  39. close(i);
  40.  
  41. if ((pid = fork()) < ) {
  42. printf("error fork\n");
  43. exit();
  44. } else if (pid != ) {
  45. exit();
  46. }
  47.  
  48. }
  49.  
  50. int main()
  51. {
  52. daemonize();
  53. while() {
  54. printf("111111111111111\n");
  55. sleep();
  56. }
  57.  
  58. }

  

多进程编程之守护进程Daemonize的更多相关文章

  1. Unix环境高级编程(十三)守护进程

    守护进程也称为精灵进程是一种生存期较长的一种进程.它们独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件.他们常常在系统引导装入时启动,在系统关闭时终止.unix系统有很多守护进程,大多数 ...

  2. python 之 并发编程(守护进程、互斥锁、IPC通信机制)

    9.5 守护进程 主进程创建守护进程 其一:守护进程会在主进程代码执行结束后就立即终止 其二:守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic process ...

  3. Linux编程实现守护进程

    Linux 守护程序 守护进程(Daemon)它是在一个特定的过程的背景进行.它独立于控制终端的和周期性地执行某些任务或待某些事件.是一种非常实用的进程. Linux的大多数server就是用守护进程 ...

  4. Unix环境高级编程:守护进程

    参考 Unix环境高级编程,第9,13章 介绍 守护进程就是Linux中使用ps aux那些一般以d结尾的程序,比如rsyslogd,sshd等,为daemon简称.他们是长期在后台执行的随终端关闭而 ...

  5. 高级UNIX环境编程13 守护进程

    linux下,keventd守护进程为内核中运行的执行的函数提供进程上下文 bdflush,kupdated将高速缓存中的数据冲洗到磁盘上

  6. Linux系统编程之--守护进程的创建和详解【转】

    本文转载自:http://www.cnblogs.com/mickole/p/3188321.html 一,守护进程概述 Linux Daemon(守护进程)是运行在后台的一种特殊进程.它独立于控制终 ...

  7. python并发编程之守护进程、互斥锁以及生产者和消费者模型

    一.守护进程 主进程创建守护进程 守护进程其实就是'子进程' 一.守护进程内无法在开启子进程,否则会报错二.进程之间代码是相互独立的,主进程代码运行完毕,守护进程也会随机结束 守护进程简单实例: fr ...

  8. [linux] C语言Linux系统编程-做成守护进程

    守护进程: 必须是init进程的子进程,运行在后台,不与任何控制终端相关联. 通过以下步骤成为守护进程 1.调用fork()创建出来一个新的进程,这个新进程会是将来的守护进程 2.在新守护进程的父进程 ...

  9. linux系统编程:守护进程详解及创建,daemon()使用

    一,守护进程概述 Linux Daemon(守护进程)是运行在后台的一种特殊进程.它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件.它不需要用户输入就能运行而且提供某种服务,不是对整个 ...

随机推荐

  1. Python distribute到底使用package_data还是MANIFEST.in?

    今天看Flask的文档,里面提到如何通过distribute发布你自己的Python包.讲包含文件的时候,提到要用MANIFEST.in并将include_package_data设置为True. 由 ...

  2. 应用.NET控制台应用程序开发批量导入程序。

    一.最近一直在调整去年以及维护去年开发的项目,好久没有在进行个人的博客了.每天抽了一定的时间在研究一些开源的框架,Drapper 以及NHibernate以及当前比较流行的SqlSuper框架 并进行 ...

  3. Python学习过程笔记整理(三)

    函数 -函数使用 -函数需要先定义,定义不会执行函数 -使用函数,俗称调用 -定义函数 -格式:def 函数名称(参数=默认值):,函数名称不能用大驼峰,参数可以没有 -调用函数 -格式:函数名(参数 ...

  4. SpringBoot之MongoTemplate的查询可以怎么耍

    学习一个新的数据库,一般怎么下手呢?基本的CURD没跑了,当可以熟练的增.删.改.查一个数据库时,可以说对这个数据库算是入门了,如果需要更进一步的话,就需要了解下数据库的特性,比如索引.事物.锁.分布 ...

  5. 百道Python入门级练习题(新手友好)第一回合——矩阵乘法

    题目描述 [问题描述] 编写程序,完成3*4矩阵和4*3整数矩阵的乘法,输出结果矩阵. [输入形式] 一行,供24个整数.以先行后列顺序输入第一个矩阵,而后输入第二个矩阵. [输出形式] 先行后列顺序 ...

  6. CocoStuff—基于Deeplab训练数据的标定工具【四、用该工具标定个人数据】

    一.说明 本文为系列博客第四篇,主要讲述笔者在正式使用该工具使用自定义标签标注自己的图片的过程. 二.数据整理 相信大家已经在 *占坑

  7. Influxdb配置文件详解---influxdb.conf

    官方介绍:https://docs.influxdata.com/influxdb/v1.2/administration/config/ 全局配置 1 2 reporting-disabled =  ...

  8. 分布式消息队列RocketMQ与Kafka架构上的巨大差异

    分布式消息服务 Kafka 是一个高吞吐.高可用的消息中间件服务,适用于构建实时数据管道.流式数据处理.第三方解耦.流量削峰去谷等场景,具有大规模.高可靠.高并发访问.可扩展且完全托管的特点,是分布式 ...

  9. Spring Data REST PATCH请求远程代码执行漏洞(CVE-2017-8046) 本地复现方法

      #1背景 Spring Data REST是Spring Data项目的一部分,可以轻松地在Spring Data存储库之上构建超媒体驱动的REST Web服务. 恶意的PATCH请求使用精心构造 ...

  10. nginx正向vs反向代理

    1.概述 nginx的正向代理,只能代理http.tcp等,不能代理https请求.有很多人不是很理解具体什么是nginx的正向代理.什么是反向代理.下面结合自己的使用做的一个简介: 1)正向代理: ...