daemon的内部整体流程是啥?
daemon函数作为一个函数,在封装好的同时,容易让初学者只知其然而不知其所以然,往往导致bug横生,让人怨声载道。
实际上,它的流程可以等效为:
1.fork()创建子进程,继承父进程的资源
2.setsid()创建会话,让子进程脱离父进程的进程组、会话组。自己开一个新的会话组当领头进程。退出父进程。
3.fork()再次创建子进程,禁止打开控制终端。退出父进程。
4.chdir()是否改变子进程工作路径。
5.umask()设置权限掩码。给子进程能够访问操作用户文件的权限。
6.关闭输入输出、错误流,减少资源浪费。
(一) 创建子进程,继承父进程的资源
子进程拷贝了父进程的代码段与数据段,然后父进程退出,在shell终端造成了程序终止的假象。实际上仍然有这么一个子进程在运行。
(二)创建会话,让子进程脱离父进程的进程组、会话组
为什么要这么做呢?
进程组:一个或多个进程的集合。每个进程组有一个领头进程。进程组是一个或多个进程的集合,通常它们与一组作业相关联,可以接受来自同一终端的各种信号。进程组PGID是进程组组长的PID。父进程能够设置自己与子进程的进程组PGID。
会话:一个或多个进程组的集合。例如我们利用Xshell等远程登录软件,每打开一个窗口就是一次会话。
因为一个父进程启用子进程后,两者处于同一个进程组、会话组中,由于会话对控制终端的独占性,进程同时与控制终端脱离。所以用setsid函数重新开一个进程组、会话期,子进程成为进程组组长、会话期的首进程。它就能脱离原有的会话与进程组了。
(三)再次创建子进程,彻底摆脱控制终端
控制终端是啥?
控制终端一般是我们创建进程的登录终端。
由于子进程是会话组的首进程,它仍然能够重新打开控制终端,所以可以再次fork一个新的子进程,这样它就无法打开控制终端了。
(四)改变进程的工作路径
如果不改变,进程将一直在程序所在的路径下运行,所在路径下的文件系统不能删除。而如果选择挂载到根目录下,就可能由于权限问题无法操作文件。
(五)设置权限掩码。给子进程能够访问操作用户文件的权限
文件权限掩码是啥?
文件权限掩码是指屏蔽掉文件权限中的对应位,比如说文件file.txt权限为444,那么它的掩码就是333.
为了便于现在的这个进程能够访问其他文件,以便程序所需,使用umask函数,设置掩码,给予它的权限。
(六)关闭输入输出、错误流,减少资源浪费
作业:shell分前后台控制会话或者进程组而不是进程。作业控制:shell可以运行一个前台作业与多个后台作业。
为什么只有一个前台作业?
在前台启动一个进程后,shell就被挂后台了,我们无法再输入命令进行解析;如果前台进程退出了,shell就会被提到前台,就可以继续接收输入命令进行解析了。
由于我们打算将进程挂到后台去,那么我们在前台的信息打印等,实际上就没什么作用了,为了减少资源浪费,我们可以使用重定向将输入输出错误流重定向到dev空洞文件去。