查看原文
其他

Daemon 进程的创建

Linux爱好者 2021-08-09

(给Linux爱好者加星标,提升Linux技能

作者:Liao Tonglang

https://quant67.com/post/linux/daemon_create.html

Daemon 进程生命周期长且在后台运行。编写daemon进程需要遵循哪些规则呢?


1、执行fork()函数,父进程退出,子进程继续


执行这一步,原因有两个:

  • 父进程可能是进程组的组长,从而不能够执行后面要执行的setsid函数。


    子进程继承了父进程的进程组ID,一定不会是进程组组长,所以子进程一定可以执行setsid。


  • 如果daemon是从终端命令行启动的,那么父进程退出后,shell会显示shell提示符,让子进程在后台执行。



2、子进程执行下面三个步骤


  • 修改当前目录为根目录 如果当前工作路径上包含根文件系统以外的文件系统,那么这个文件系统将不能被卸载。


    当然也可以改成其它合适的目录。这里使用函数chdir("/")。


  • 调用setsid 这是为了切断与控制终端的所有关系,创建一个新的会话。


    此时无论终端是否发送SIGIN、SIGQUIT或者SIGTSTP或者断开,都与daemon进程无关。


  • 使用umask(0)设置文件模式创建掩码为0 这一步的目的是让daemon进程创建文件的权限属性与shell脱离关系。


    因为默认情况下,进程的umask来源于父进程shell的umask。如果不执行umask(0),那么父进程的shell就会影响daemon,造成daemon每次执行的umask信息不一致。


3、再次执行fork,父进程退出,子进程继续


执行完前面两步之后,新建了会话,进程是会话的首进程,也是进程组的首进程;进程ID,进程组ID,会话ID相同;进程和终端失去联系。


但是还差一步。daemon进程有可能会打开一个终端设备:

int fd = open("/dev/console", O_RDWR);
这个设备是否会成为daemon进程的控制终端,取决于两点:
  • daemon进程是不是会话的首进程。

  • 系统实现。(BSD的实现不会成为daemon的控制终端,但POSIX由具体实现决定)。

为了万无一失,需要使用fork()确保daemon不是会话的首进程。



4、关闭stdin,stdout,stderr


关闭之后应该打开/dev/null将0,1,2描述符指向它。这是为了防止后面执行0,1,2上的I/O时出现错误。


C库的daemon函数和这个流程相似,但没有第二次fork。


- EOF -

推荐阅读  点击标题可跳转

1、Linux - 请允许我静静地后台运行

2、网络故障排除工具 | 快速定位网络故障

3、Shell 监控文件变化


看完本文有收获?请分享给更多人

推荐关注「Linux 爱好者」,提升Linux技能

点赞和在看就是最大的支持❤️

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存