# Linux daemon进程 # 什么是daemon进程 daemon进程是指长时间运行在后台的进程,也叫守护进程. 为什么会有daemon进程? 由于控制终端的原因(例如断开终端连接)会产生一些信号, 进程接受到这些信号的缺省动作是让进程退出. daemon进程的特点: 没有控制终端,在后台运行 # 实现daemon进程的方法 ``` pid_t pid = fork(); if( pid != 0 ) { exit(0);//parent } //first children printf("first child: PID: %d\n", getpid()); if(setsid() == -1) { printf("setsid failed\n"); assert(0); exit(-1); } umask(0); pid = fork(); if( pid != 0) { exit(0); } //second children printf("second child: PID: %d\n", getpid()); chdir ("/"); for (int i = 0; i < 3; i++) { close (i); } int stdfd = open ("/dev/null", O_RDWR); dup2(stdfd, STDOUT_FILENO); dup2(stdfd, STDERR_FILENO); ``` * 第一次fork 结束父进程,让init进程托管该进程,从而进入后台运行 * setsid 脱离控制终端,登录会话和进程组 进程属于一个进程组,进程组号(GID)就是进程组长的进程号(PID)。登录会话可以包含多个 进程组。这些进程组共享一个控制终端。控制终端,登录会话和进程组是从父进程继承下来的. 调用setsid后,The calling process将会成为: 1. the leader of the new session, the 2. the process goup leader of the new process group 3. has no controlling terminal 新的group ID 和 session ID就是the calling process的PID 只有在calling process不是进程组长时,setsid才会创建一个新的session, 所以在setsid之前 必须要通过fork保证调用进程不是group leader * umask(0) 重设文件掩码, 由于fork会从父进程继承文件创建掩码,所以将文件创建掩码清0 * 第2次fork 主要目的: 防止进程再次打开一个控制终端 因为打开一个控制终端的前提条件是:“该进程必须是会话组长”, 再fork一次之后,进程ID就不 等于sid了,所以也就无法打开新的控制终端。 * chdir("/") 由于fork会继承当前的工作目录,当进程没有结束时,其工作目录是不能被卸载的, 为了防止这种情况,守护进程一般会将工作目录改变到根目录下. * 关闭文件描述符,并重定向标准输出、错误 fork得到的进程会继承父进程打开的文件描述符,所以需要将他们关闭. 由于守护进程在后台运行,所以不应该在终端有任何输出信息,将标准输出和标准错误重定向到 /dev/null # 守护进程与&结尾的后台运行程序的区别 * 守护进程已经完全脱离控制台,而后台进程并没有完全脱离终端. 在终端未关闭之前仍然会从终端 输出结果 * 守护进程在关闭终端控制台时不会受影响,而后台程序将会停止. * 守护进程的会话组、工作目录、文件描述符都是独立的,而后台程序这些都没有改变