多进程编程之守护进程Daemonize
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()函数创建一个新的会话:
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的更多相关文章
- Unix环境高级编程(十三)守护进程
守护进程也称为精灵进程是一种生存期较长的一种进程.它们独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件.他们常常在系统引导装入时启动,在系统关闭时终止.unix系统有很多守护进程,大多数 ...
- python 之 并发编程(守护进程、互斥锁、IPC通信机制)
9.5 守护进程 主进程创建守护进程 其一:守护进程会在主进程代码执行结束后就立即终止 其二:守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic process ...
- Linux编程实现守护进程
Linux 守护程序 守护进程(Daemon)它是在一个特定的过程的背景进行.它独立于控制终端的和周期性地执行某些任务或待某些事件.是一种非常实用的进程. Linux的大多数server就是用守护进程 ...
- Unix环境高级编程:守护进程
参考 Unix环境高级编程,第9,13章 介绍 守护进程就是Linux中使用ps aux那些一般以d结尾的程序,比如rsyslogd,sshd等,为daemon简称.他们是长期在后台执行的随终端关闭而 ...
- 高级UNIX环境编程13 守护进程
linux下,keventd守护进程为内核中运行的执行的函数提供进程上下文 bdflush,kupdated将高速缓存中的数据冲洗到磁盘上
- Linux系统编程之--守护进程的创建和详解【转】
本文转载自:http://www.cnblogs.com/mickole/p/3188321.html 一,守护进程概述 Linux Daemon(守护进程)是运行在后台的一种特殊进程.它独立于控制终 ...
- python并发编程之守护进程、互斥锁以及生产者和消费者模型
一.守护进程 主进程创建守护进程 守护进程其实就是'子进程' 一.守护进程内无法在开启子进程,否则会报错二.进程之间代码是相互独立的,主进程代码运行完毕,守护进程也会随机结束 守护进程简单实例: fr ...
- [linux] C语言Linux系统编程-做成守护进程
守护进程: 必须是init进程的子进程,运行在后台,不与任何控制终端相关联. 通过以下步骤成为守护进程 1.调用fork()创建出来一个新的进程,这个新进程会是将来的守护进程 2.在新守护进程的父进程 ...
- linux系统编程:守护进程详解及创建,daemon()使用
一,守护进程概述 Linux Daemon(守护进程)是运行在后台的一种特殊进程.它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件.它不需要用户输入就能运行而且提供某种服务,不是对整个 ...
随机推荐
- UWP DEP0700: 应用程序注册失败。[0x80073CF9] 另一个用户已安装此应用的未打包版本。当前用户无法将该版本替换为打包版本。
最近电脑抽风,我在[应用程序和功能]中重置了以下我的App自然灾害,居然,搞出大新闻了. 它居然从列表中消失了... vs再次编译代码的时候,提示 严重性 代码 说明 项目 文件 行 禁止显示状态 错 ...
- js获取字符串字节数方法小结
js获取字符串字节数的方法.分享给大家供大家参考.具体如下: 大家都知道,获取字符串的长度可用length来获取,那么获取这段字符串的字节数呢? 英文字母肯定lenght和字节数都一样:都是1而中文l ...
- NO 18---- webpack 4.x 使用遇到的问题以及开发配置
最近在项目中用webpack的过程中老是出现问题,很是纳闷,按理说一直这样使用没有问题啊,经过我研究后发现,是因为在webpack更新到4.x之后,操作方式与之前相比变化很大.而我们使用npm默认安装 ...
- docker入门使用教程
Docker概念 Docker是开发人员和系统管理员 使用容器开发,部署和运行应用程序的平台.使用Linux容器部署应用程序称为容器化.容器不是新的,但它们用于轻松部署应用程序. 容器化越来越受欢迎, ...
- prometheus-operator 监控 Rabbitmq集群
首先我们监控服务需要知道prometheus-operator是如何去工作的,才好去写相关的yaml配置,这里我划分成了5个部分,如果容器服务本身就以k8s来编排的,那就只需要三步,这里因为我的rab ...
- redis使用Jackson2JsonRedisSerializer序列化问题
一.spring boot 集成Redis方法 依赖 <!--redis--> <dependency> <groupId>org.springframework. ...
- 《The Mythical Man-Month(人月神话)》读后感(2)
第10章 未雨绸缪 在化学领域中,在实验室可以进行的反应过程,并不能在工厂中一步实现.一个被称为“ 实验性工厂(pilot planet)”的中间步骤是非常必要的,它会为提高产量和在缺乏保护的环境下运 ...
- The Art of Multiprocessor Programming读书笔记 (更新至第3章)
这份笔记是我2013年下半年以来读“The Art of Multiprocessor Programming”这本书的读书笔记.目前有关共享内存并发同步相关的书籍并不多,但是学术文献却不少,跨越的时 ...
- python其他知识目录
博客目录总纲首页 基础的重要性(程序员之路) 做一个“合格”的程序员(一)——基础能力 作为一个程序员,数学对你到底有多重要 同样是程序员,为什么别人比你更优秀? ------------------ ...
- Centos7 Jenkins
代码上线 持续集成 随时随地将代码合并,这种方法叫做持续集成. 持续集成(CONTINUOUS INTEGRATION,简称CI)持续集成指的是,频繁地(一天多次)将代码集成到主干.它的好处主要有两个 ...