本文共 2134 字,大约阅读时间需要 7 分钟。
本文介绍了守护进程的概念及其模拟实现
Key Point:
模拟实现守护进程(Code):
调用函数模拟实现mydaemon 调用系统接口实现
~tips:全文阅读需要5min~
守护进程(精灵进程( Daemon)):
Linux的大多数服务器就是用守护进程实现的:
比如Internet服务器inetd,Web服务器httpd等;同时,守护进程还可以完成许多系统任务,比如作业规划进程crond,想了解的小伙伴请戳下面:
用ps axj命令查看系统中的进程:参数a表示不仅列当出前用户的进程,也列出所有其他用户的进程;参数x表示不仅列有控制终端的进程,也列出所有无控制终端的进程;参数j表示列出与作业控制相关的信息。
凡是TPGID⼀栏写着-1的都是没有控制终端的进程,也就是守护进程。守护进程通常采⽤以d结尾的名字,表示Daemon。
注:在COMMAND一列⽤用[]括起来的名字表示内核线程,这些线程在内核⾥里创建,没有用户空间代码,因此没有程序文件名和命令行, 通常采用以k开头的名字,表示Kernel。
1. 调用setsid函数实现mydaemon
创建守护进程最关键的一步是就是调用setsid函数创建一个新的会话Session,并使该进程成为Session Leader:
该函数调用成功时返回新创建的Session的id(其实也就是当前进程的id),出错返回-1:
成功调⽤用该函数的结果是:
所谓失去控制终端是指,原来的控制终端仍然是打开的,仍然可以读写,但只是⼀个普通的打开⽂件操作而不是控制终端了。
下面我们编写代码mydaemon.c
step1:声明mydaemon();函数
因为守护进程的目标是提供服务,并非使其成为守护进程。所以用while(1)代表所提供的服务
step2:调用umask设置文件掩码为0.
将文件模式创建屏蔽字设置为0,以防服务中涉及文件读写
step3:fork()创建子进程后调用setsid()函数.
由于setsid()函数之前,当前进程不允许是进程组的Leader,否则该函数返回-1。所以要保证当前进程不是进程组的Leader就要先fork再调用setsid。
此时fork创建的子进程和父进程在同一个进程组中,进程组的Leader必然是该组的第一个进程,所以子进程就不可能是该组的第一个进程。在子进程中调用setsid就不会有问题了。
注意这里父进程退出(exit)原因:
1. 如果该守护进程是作为一条简单的shell命令启动的,那么父进程终止使得shell认为该命令已经执行完毕。2. 保证子进程不是一个进程组的组长进程
step3:完成其他操作
step4:再fork一次
再次fork,终止父进程,在while后时刻保证子进程不是话首进程,从而保证后续不会在和其他终端关联。维持daemon进程的特点。
好了,代码写完了,接下来我们运行程序。测试一下是否创建了一个守护进程。
1.查看父进程是否为1:
2.打开proc目录(进程信息以文件系统的方式呈现,实时目录)查看cwd(当前工作目录)是否改为“/”
3.查看fd目录中文件描述符是否已关闭:
可以看到,的确创建了一个pid为32650的守护进程。
删掉守护进程:kill -9 pid(上级pid目录不存在)
此外,step3中对文件描述符的操作还可以有另一种方法,那就是把它们移到 /dev/null目录中。 /dev/null目录是一个保存垃圾数据的目录,凡是写到其中的数据全会被丢弃。
不要忘记加头文件:
运行程序后,再次打开fd目录,发现文件描述符已经重定向到了/dev/null目录中:
文件描述符也依然存在:
2. 调用系统接口daemon函数实现
除了调用setsid函数外,还可以利用系统提供的daemon函数来创建守护进程:
2参数的默认值均为0
代码如下:
运行程序:
上边的结果表明,系统创建守护进程时,对文件描述符的处理方式是刚才的第二种。这在该函数的描述中也可以看到:
以上就是本文全部内容,如有不足之处,还请各位大神不吝赐教。