创建一个简单的守护进程

1.概念

守护进程也称精灵进程,是在后台运行的一种特殊进程,它脱离控制终端并且周期性的执行某种任务或者等待某种事件的发生,脱离终端是为了避免进程在执行过程中的信息在任何终端上显示,并且进程也不会被任何终端产生的中断信息所终止;linux下的大多 服务器都是用守护进程实现的。比如internet 的inted 和wed 服务器httpd

2.创建守护进程的一般步骤

(1)调用umask重设文件权限掩码

文件权限掩码:指屏蔽掉文件权限中的对应位。例如,有个文件权限掩码为050,它就屏蔽掉了文件组拥有者的可读与可执行权限。由于 fork创建的子进程继承了父进程的文件掩码,这给子进程使用文件带来了麻烦,因此将文件掩码设置为0(即不屏蔽任何权限)可以增强守护进程的灵活性

(2)创建子进程退出父进程

为了脱离控制终端需要推测出父进程,之后的工作由子进程完成。在linux中父进程先与子进程退出会造成孤儿进程,每当发现一个孤儿进程 时就会自动由1号进程(init)收养它,这样原先的子进程就会变成init的子进程

(3)调用setid(void)函数在子进程中创建一个新会话

man 2 setsid    查看关于setsid函数的说明

setsid – creates a session and sets theprocess group ID

#include <unistd.h>

pid_t setsid(void);

setsid() creates a new session if thecalling process is not a process group leader. The calling process is theleader of the new session, the process group leader of the new process group,and has no controlling tty. The process group ID and session ID of the callingprocess are set to the PID of the calling process. The calling process will bethe only process in this new process group and in this new session.

进程组:一个或多个进程的集合,进程组由进程组的ID来唯一标示 ,每个进程组都有一个组长进程,其组长进程的进程号等于进程组ID,该进程组ID不会因为组长进程退出而受到影响

setid函数的作用:用于创建一个新的会话,并担任该会话组的组长,其中有以下三个作用

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

b.让进程摆脱原来会话组的控制

c.让进程摆脱原来会话终端的控制

使用setid函数的目的

由于创建守护进程第一步调用了fork函数创建子进程再将父进程退出。由于在调用fork函数的时候,子进程拷贝了父进程的会话期,进程组,控制终端等,虽然父进程退出了但是会话期,进程组,控制终端没有改变,因此还不是真正意义上独立了。使用ssetid函数之后能够使进程完全独立出来,从而摆脱其他进程的控制。

(4)改变当前目录为根目录

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

(5)关闭文件描述符

用fork创建的子进程会从父进程哪里继承一些已经打开 的文件。这些打开的文件可能永远不会被守护进程读写,但他们一样消耗资源。在使用setid后守护进程已经与 所属的控制终端失去联系,因此终端输入的进程不可能到达守护进程。所以文件描述符0,1,2已经失去了存在 的价值应该关闭

(6)守护进程的退出处理

当用户需要外部停止守护进程时,通常用kill命令停止该守户进程

  1 #include<stdio.h>                                                           
  2 #include<signal.h>
  3 #include<unistd.h>
  4 #include<stdlib.h>
  5 #include<fcntl.h>
  6 #include<sys/stat.h>
  7 
  8 void creat_daemon(void){
  9 int i;
10 int fd0;
11 pid_t pid;
12 struct sigaction sa;
13 umask(0);//设置文件掩码为0
14     if(pid=fork()<0){
15         printf("child dir error\n");
16     }
17         else {
18         exit(0);//
19         }
20 
21 setid(0);//设置新的会话
22 sa.sa_handler=SIG_IGN;
23 sigemptyset(&sa.sa_mask);
24 sa.sa_flags=0;
25 if(sigaction(SIGCHLD,&sa,NULL)<0){//注册子进程退出忽略信号 
26 return;
27 }
28 if(pid=fork()<0){//再次fork,终止父进程保证子进程不是话首进程,保证进程不会受到其他进程的干扰
29 printf("fork error!\n");
30 return;
31 }
32 else if(pid!=0){
33 exit(0);
34 }
35 
36 if(chdir("/")<0){//更改工作目录到根目录
37 printf("child dir error\n");                                                
38 return;
39 }
40 close(0);
41 fd0=open("/dev/null",O_RDWR);//关闭标准输入 ,标准输出,标准错误
42 dup2(fd0,1);
43 dup2(fd0,2);
44 }
45 
46 int main()
47 {
48 creat_daemon();
49 while(1){
50 sleep(1);
51 
52 }
53 
54 }
55

那么问题来了,daemon 函数为什么会fork两次?????

原因如下:

(1)第一次fork是为了让shell认为本条命令已经终止,不用挂在输入端。还有一个为后边的setid服务。setid的调用者不能是进程组组长,此时父进程是进程组组长

(2)setid是daemon函数中的一个重要的调用,它完成了daeemon函数要做的大部分事情调用完之后子进程是会话组组长,并且脱离了原来终端的控制,以后不官终端如何新的进程都不会受到那些信号

(3)第二次fork的目的是为了防止进程再次打开一个控制 终端。因为打开一个控制终端的前提条件是该进程必须是会话组组长。再fork一次子进程id!=ppid所以也无法打开新的控制终端

时间: 2024-07-30 13:38:09

创建一个简单的守护进程的相关文章

一个简单的守护进程

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <fcntl.h> #define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); }while(0) int main(int argc, const char *argv[

如何利用CEF3创建一个简单的应用程序 (Windows Platform)

1. 说明 这篇文章主要讲述如何利用CEF3来创建一个简单的应用程序,引用的是1535及以上版本中包含的 Cefsimple 项目例子.如果想知道关于CEF3更多的使用方法,可以去访问 GeneralUsage. 2. 开始 首先,根据自身所使用的开发平台,可以去 这里 下载对应的发布版本.针对这个教程,我们需要下载1750或者更新的版本.当前支持的平台有Windows, Linux和Mac OS X.每一个版本都包含了当在特定平台上编译特定版本CEF3时所需要的所有文件和资源.您可以通过包含在

IntelliJ IDEA 15 部署Tomcat及创建一个简单的Web工程

一.部署Tomcat 二.创建一个简单的Web工程 2.1创建一个新工程 创建一个新工程 设置JDK及选择Web Application (创建的是Web工程) 点击Next,选择工作空间,起个工程名 2.2项目部署 在工具栏点击 Project: 无需任何设置,选择默认编译目录(或自定义编译目录) Modules: 将Tomcat加入 Libraries:无需任何设置.这里描述了此项目的依赖. Facets: 无需任何设置.这里描述了此项目所适配的服务框架 Artifacts: 无需任何配置.

mysql 如何创建一个简单的存储过程

1 用mysql客户端登入2 选择数据库 mysql>use test3 查询当前数据库有哪些存储过程 mysql>show procedure status where Db='test'4 创建一个简单的存储过程 mysql>create procedure hi() select 'hello'; 5 存储过程创建完毕,看怎么调用它 mysql>call hi();显示结果 mysql> call hi(); +-------+ | hello | +-------+

《Entity Framework 6 Recipes》翻译系列 (3) -----第二章 实体数据建模基础之创建一个简单的模型 (转)

第二章 实体数据建模基础 很有可能,你才开始探索实体框架,你可能会问“我们怎么开始?”,如果你真是这样的话,那么本章就是一个很好的开始.如果不是,你已经建模,并在实体分裂和继承方面感觉良好,那么你可以跳过本章. 本章将带你漫游使用实体框架建模的基本实例,建模是实体框架的核心特性,同时也是区别实体框架和微软早期的数据访问平台的特性.一旦建好模,你就可以面向模型编写代码,而不用面向关系数据库中的行和列. 本章以创建一个简单概念模型的实例开始,然后让实体框架创建底层的数据库,剩下的实例,将向你展示,如

[安卓基础] 005.创建一个简单的UI

*:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } a { color: #4183C4; text-decoration: none; } a.absent { color: #cc0000; } a.anchor { display: block; padding-left: 30px; margin-left: -30px; cursor: poin

SharePoint 创建一个简单的Web Part 部分

SharePoint 创建一个简单的Web Part 部分 标准Web零件有时会很强大,运行多个功能的能力. 本文介绍了如何使用Visual Studio 创建一个简单的Web部分. 1. 打开VS,点击文件----新建项目. 2. 选择空白SharePoint项目.命名SmallvilleWebPartProject,点击确定.选择部署为场解决方式. 3. 右击项目加入新项目. 4. 选择Web部件. 5. 命名CustomerInformation,点击加入. 6. 右击新的Web部件项目.

Highcharts创建一个简单的柱状图

新建一个html文件,将highcharts引入到你的页面后,通过两个步骤我们就可以创建一个简单的图表了. 1.创建div容器 在页面的 body部分创建一个div,并指定div 的 id,高度和宽度,代码如下 <div id="container" style="min-width:800px;height:400px"></div> 2.编写Highcharts代码 编写Highcharts必须的代码,用<script><

SharePoint创建一个简单的Visio Web部件图

SharePoint创建一个简单的Visio Web部件图 Visio有许多强大的Mash-up混聚功能,使它可以轻松集成到SharePoint 2010中. 1. 打开Visio 2010,创建新的ITIL图. 2. 绘图如下: 3. 点击后台选项卡(左上角). 4. 点击另存为,选择位置,点击确定,输入Keyword,点击确定. 5. 在页面上添加Web部件. 6. 编辑Web部件,将上图的URL填上去. SharePoint创建一个简单的Visio Web部件图,布布扣,bubuko.co