1、守护进程

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

2、编程规则

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

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

 #include <sys/stat.h>

 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,输出结果如下图

 #include <stdio.h>
#include <sys/stat.h> int main()
{
umask();
if (creat("fan_test1",S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) < )
printf("error creat\n");
umask(S_IROTH|S_IWOTH);
if (creat("fan_test2",S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) < )
printf("error creat\n");
return ;
}

    

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

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

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

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

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

  关闭文件描述符的方法:

 方法1:
#include <sys/resource.h> struct rlimit rl; 6 if(getrlimit(RLIMIT_NOFILE, &rl) < )
7 {
perror("getrlimit(RLIMIT_NOFILE, &rl)");
return -;
10 }
11 if(rl.rlim_max == RLIM_INFINITY)
12 {
13 rl.rlim_max = ;
14 }
15 for(i = ; i < rlim_max; i++)
{
close(i);
}
方法2:
max_fd = sysconf(_SC_OPEN_MAX);
for(i = ; i < max_fd; i++)
{
close(i);
}

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

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

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

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

实现一个守护进程:

 #include <stdio.h>
#include <sys/stat.h>
#include <signal.h>
#include <sys/resource.h>
#include <unistd.h>
#include <stdlib.h>
void daemonize(void)
{
struct rlimit rl;
pid_t pid;
struct sigaction sa;
int i;
umask();
if (getrlimit(RLIMIT_NOFILE, &rl) < ) {
printf("error getrlimit\n");
exit();
}
if ((pid = fork()) < ) {
printf("error fork\n");
exit();
} else if (pid != ) {
exit();
}
setsid();
sa.sa_handler = SIG_IGN;
sigemptyset(&sa.sa_mask);
sa.sa_flags = ;
if (sigaction(SIGHUP, &sa, NULL) < ) {
printf("error sigaction\n");
exit();
}
if (chdir("/") < ) {
printf("error chdir\n");
exit();
}
if (rl.rlim_max == RLIM_INFINITY)
rl.rlim_max = ;
for (i = ; i < rl.rlim_max; i++)
close(i); if ((pid = fork()) < ) {
printf("error fork\n");
exit();
} else if (pid != ) {
exit();
} } int main()
{
daemonize();
while() {
printf("111111111111111\n");
sleep();
} }

  

多进程编程之守护进程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. SpringBoot日记——日志框架篇

    在项目的开发中,日志是必不可少的一个记录事件的组件,所以也会相应的在项目中实现和构建我们所需要的日志框架. 而市面上常见的日志框架有很多,比如:JCL.SLF4J.Jboss-logging.jUL. ...

  2. React——JSX

    一.将表达式嵌套在JSX中 要在JSX中内嵌js表达式只需要将js表达式放在{}中,例如: const element = <h1>this is a JSX {sayName()}< ...

  3. java练习(一)数组、集合的运用

    有这么一个有趣的问题,问:有这么一个不重复的自然数数组,自然数长度为N,而数组长度为N-2,依次随机把自然数放进数组中,请找出2个没有被放进去的自然数.例如:这个自然数数组是[0, 1, 2, 3,  ...

  4. move.js运动插件

    move.js 运动插件是一款针对元素动画效果的插件.可以运用此插件制作出各类元素效果. 插件GitHub地址:https://github.com/visionmedia/move.js 下面整理学 ...

  5. 《Redis设计与实现》阅读笔记(一)--Redis学习

    Redis学习资料与过程记录 在实习中经常会用到很多Redis,对Redis有了一些模糊的了解,总觉得隔靴搔痒的不痛快,所以决定开始深入的了解Redis,也作为我实习期间的目标. 这篇只是为了占个位置 ...

  6. MYSQL数据库与Emoji表情的故事

    问题背景 手机上众多输入法和键盘支持输入 emoji 表情,给早期设计的程序造成了越来越多的干扰. 移动端购物的流行,2018 年 "双十一"全网移动端交易达到 93.6% 微信年 ...

  7. 团队冲刺--six

    昨天: 司宇航:合并版块,但部分有缺陷. 马佳慧:研究css. 王金萱:写注册界面. 季方:  研究爬虫,精确的处理数据. 今天: 司宇航:测试功能版块,优化功能版块. 马佳慧:优化界面 . 王金萱: ...

  8. C++自学随笔(2)

    引用 就像人的别名,人不能只有别名,变量也不能只有引用. 指针类型的引用:*&指针引用名 = 指针. 如int a = 10;int *p =&a;int *&q =p1 co ...

  9. c++第七次作业____最后的总结

    先言: 在这过程中学到: 第二次作业Github的使用 第四次作业计算器的计算 ps:表达式处理以及计算 第五次作业文件的处理问题 第六次作业界面的设计 总结: 1.这学期的计算器,做的有点匆忙,偶尔 ...

  10. python字符串操作、文件操作,英文词频统计预处理

    1.字符串操作: 解析身份证号:生日.性别.出生地等. 凯撒密码编码与解码 网址观察与批量生成 解析身份证号:生日.性别.出生地等 def function3(): print('请输入身份证号') ...