linux:守护进程&模拟实现mydaemon

来源:互联网 发布:简明python教程 中文 编辑:程序博客网 时间:2024/06/05 16:48

ForeWord


本文介绍了守护进程的概念及其模拟实现

Key Point:

  1. 守护进程(Daemon)概念
  2. 模拟实现守护进程(Code):

     调用函数模拟实现mydaemon 调用系统接口实现

~tips:全文阅读需要5min~


Daemon


守护进程(精灵进程( Daemon)):

  1. 一种没有控制终端的linux系统服务进程,父进程为pid为1的init进程,随系统启动。
  2. 不能直接和用户交互,不受用户登录注销的影响,一直在运行。
  3. 独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。

Linux的大多数服务器就是用守护进程实现的:

   比如Internet服务器inetd,Web服务器httpd等;同时,守护进程还可以完成许多系统任务,比如作业规划进程crond,想了解的小伙伴请戳下面:

作业控制&作业规划进程crond

ps axj命令查看系统中的进程:参数a表示不仅列当出前用户的进程,也列出所有其他用户的进程;参数x表示不仅列有控制终端的进程,也列出所有无控制终端的进程;参数j表示列出与作业控制相关的信息。

1

凡是TPGID⼀栏写着-1的都是没有控制终端的进程,也就是守护进程。守护进程通常采⽤以d结尾的名字,表示Daemon。

注:在COMMAND一列⽤用[]括起来的名字表示内核线程,这些线程在内核⾥里创建,没有用户空间代码,因此没有程序文件名和命令行, 通常采用以k开头的名字,表示Kernel。


Code:模拟实现Daemon


1. 调用setsid函数实现mydaemon

创建守护进程最关键的一步是就是调用setsid函数创建一个新的会话Session,并使该进程成为Session Leader:

2

该函数调用成功时返回新创建的Session的id(其实也就是当前进程的id),出错返回-1:

3

成功调⽤用该函数的结果是:

  1. 创建一个新的Session,当前进程成为Session Leader。当前进程的id就是Session的id。
  2. 创建一个新的进程组,当前进程成为进程组的Leader。当前进程的id就是进程组的id。
  3. 如果当前进程原本有一个控制终端,则它失去这个控制终端。成为⼀个没有控制终端的进程。这也是守护进程概念中的特点之一。

所谓失去控制终端是指,原来的控制终端仍然是打开的,仍然可以读写,但只是⼀个普通的打开⽂件操作而不是控制终端了。

下面我们编写代码mydaemon.c

step1:声明mydaemon();函数

因为守护进程的目标是提供服务,并非使其成为守护进程。所以用while(1)代表所提供的服务

4

step2:调用umask设置文件掩码为0.

将文件模式创建屏蔽字设置为0,以防服务中涉及文件读写

5

step3:fork()创建子进程后调用setsid()函数.

由于setsid()函数之前,当前进程不允许是进程组的Leader,否则该函数返回-1。所以要保证当前进程不是进程组的Leader就要先fork再调用setsid。

6

此时fork创建的子进程和父进程在同一个进程组中,进程组的Leader必然是该组的第一个进程,所以子进程就不可能是该组的第一个进程。在子进程中调用setsid就不会有问题了。

注意这里父进程退出(exit)原因:

1. 如果该守护进程是作为一条简单的shell命令启动的,那么父进程终止使得shell认为该命令已经执行完毕。2. 保证子进程不是一个进程组的组长进程

step3:完成其他操作

  1. 更改进程工作目录到/:chdir
    此举是为了方便寻找文件,再者根目录不可能被删除,保证文件安全。且路径不可能丢失
  2. 关闭0 1 2文件描述符:close(0)/1/2
  3. 忽略SIGCHID信号:signal(SIGCHID, SIG_IGN)

7

step4:再fork一次

再次fork,终止父进程,在while后时刻保证子进程不是话首进程,从而保证后续不会在和其他终端关联。维持daemon进程的特点。

8

  好了,代码写完了,接下来我们运行程序。测试一下是否创建了一个守护进程。

1.查看父进程是否为1:

9

2.打开proc目录(进程信息以文件系统的方式呈现,实时目录)查看cwd(当前工作目录)是否改为“/”

10

3.查看fd目录中文件描述符是否已关闭:

11

  可以看到,的确创建了一个pid为32650的守护进程。

删掉守护进程:kill -9 pid(上级pid目录不存在)

12

此外,step3中对文件描述符的操作还可以有另一种方法,那就是把它们移到 /dev/null目录中。 /dev/null目录是一个保存垃圾数据的目录,凡是写到其中的数据全会被丢弃。

14

不要忘记加头文件:

13

运行程序后,再次打开fd目录,发现文件描述符已经重定向到了/dev/null目录中:

15

文件描述符也依然存在:

16

2. 调用系统接口daemon函数实现

除了调用setsid函数外,还可以利用系统提供的daemon函数来创建守护进程:

20
2参数的默认值均为0

代码如下:

17

运行程序:

18

上边的结果表明,系统创建守护进程时,对文件描述符的处理方式是刚才的第二种。这在该函数的描述中也可以看到:

25


The End


以上就是本文全部内容,如有不足之处,还请各位大神不吝赐教。

原创粉丝点击