怎么编写一个标准的 Daemon进程

参考: https://segmentfault.com/a/1190000009082089
https://segmentfault.com/a/1190000009152815

nohup是咋回事呢?nohup干了这么几件事:

   将stdin重定向到/dev/null,于是程序读标准输入将会返回EOF

   将stdout和stderr重定向到nohup.out或者用户通过参数指定的文件,
   程序所有输出到stdout和stderr的内容将会写入该文件(有时在文件中看不到输出,有可能是程序没有调用flush)

   屏蔽掉SIGHUP信号

   调用exec启动指定的命令(nohup进程将会被新进程取代,但进程ID不变)

从上面nohup干的事可以看出,通过nohup启动的程序有这些特点:

    nohup程序不负责将进程放到后台,这也是为什么我们经常在nohup命令后面要加上符号“&”的原因

    由于stdin、stdout和stderr都被重定向了,nohup启动的程序不会读写tty

    由于stdin重定向到了/dev/null,程序读stdin的时候会收到EOF返回值

    nohup启动的进程本质上还是属于当前session的一个进程组,所以在当前shell里面可以通过jobs看到nohup启动的程序

    当session leader退出后,该进程会收到SIGHUP信号,但由于nohup帮我们忽略了该信号,所以该进程不会退出

    由于session leader已经退出,而nohup启动的进程属于该session,于是出现了一种情况,
    那就是通过nohup启动的这个进程组所在的session没有leader,这是一种特殊的情况,内核会帮我们处理这种特殊情况,这里就不再深入介绍

	通过nohup,我们最后达到了就算session leader(一般是shell)退出后,进程还可以照常运行的目的。	 
	
在我的 Ubuntu 中测试:
	1. 在 shell1 中 ping -c 100 baidu.com   (注意并没有 & 符号)
	2. 在 shell2 中 ps ajx (主要想看 PGID 和 SID)
		root@robert-Ubuntu:~# $$
		2102: command not found
		root@robert-Ubuntu:~# 

	    root@robert-Ubuntu:~# ps ajx
		 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
		    1  1125  1125  1125 ?           -1 Ss       0   0:00 /usr/sbin/sshd -D
		 ....
		 1125  2264  2264  2264 ?           -1 Ss       0   0:00 sshd: root@pts/8
		 2264  2303  2303  2303 pts/8     2321 Ss       0   0:00 -bash
		 2303  2321  2321  2303 pts/8     2321 S+       0   0:00 ping -c 100 baidu.com
		 2102  2329  2329  2102 pts/9     2329 R+       0   0:00 ps ajx
	4. 把 shell 1 的窗口关闭掉
	5. 再次在shell2 中执行 ps ajx (主要想看 PGID 和 SID),发现 ping 进程并没有结束掉,仅仅是 PPID 变为 了1
		root@robert-Ubuntu:~# ps ajx
		 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
		    1  2321  2321  2303 ?           -1 S        0   0:00 ping -c 100 baidu.com 
		 2102  2341  2341  2102 pts/9     2341 R+       0   0:00 ps ajx
		root@robert-Ubuntu:~#  

daemon

	通过nohup,就可以实现让进程在后台一直执行的功能,为什么我们还要写daemon进程呢?

	从上面的nohup的介绍中可以看出来,虽然进程是在后台执行,但进程跟当前session还是有着千丝万缕的关系,至少其父进程还是被session管着的,所以我们还是需要一个跟任何session都没有关系的进程来实现deamon的功能。实现deamon进程的大概步骤如下:

    调用fork生成一个新进程,然后原来的进程退出,这样新进程就变成了孤儿进程,于是被init进程接收,这样新进程就和调用进程没有父子关系了。

    调用setsid,创建新的session,新进程将成为新session的leader,同时该新session不和任何tty关联。

    切换当前工作目录到其它地方,一般是切换到根目录,这样就取消了对原工作目录的引用,如果原工作目录是某个挂载点下面的目录,这样就不会影响该挂载点的卸载。

    关闭一些从父进程继承过来而自己不需要的fd,避免不小心读写这些fd。

    重定向stdin、stdout和stderr,避免读写它们出现错误。
发布了44 篇原创文章 · 获赞 0 · 访问量 3947

猜你喜欢

转载自blog.csdn.net/cpxsxn/article/details/102515900