如何看一个进程是不是守护进程呢?一个简单的方式是看下它的tty是不是?
比如nginx的
root@lan-dev-215:~/test# ps -e -o pid,ppid,cmd,tty | grep nginx
1436 1 nginx: master process /usr/ ?
1437 1436 nginx: worker process ?
1438 1436 nginx: worker process ?
1439 1436 nginx: worker process ?
1440 1436 nginx: worker process ?
1441 1436 nginx: worker process ?
1442 1436 nginx: worker process ?
1443 1436 nginx: worker process ?
1444 1436 nginx: worker process ?
1445 1436 nginx: worker process ?
1446 1436 nginx: worker process ?
1447 1436 nginx: worker process ?
1448 1436 nginx: worker process ?
1449 1436 nginx: worker process ?
1450 1436 nginx: worker process ?
1451 1436 nginx: worker process ?
1452 1436 nginx: worker process ?
可以看到它的tty都是?
上次介绍了守护进程的一个工具tmux,今天介绍linux的daemon
daemon
daemon是干啥的,man看一下
man daemon
回到上次那个例子,我们改下代码便于观察。
#include <stdio.h>
main(void)
{
int d = 1;
while(1){
printf("hello %d \n",d);
fflush(stdout);
sleep(1);
d += 1;
};
return 0;
}
gcc编译后,使用daemon命令运行a.out
daemon --name=test_daemon --respawn -o /tmp/test.log -- /root/test/a.out
这里用了三个参数:name 和 -o 。name是取个daemon的名字,-o是指定标准输出的文件,–respawn 重启进程
root@lan-dev-215:~/test# ps aux | grep a.out
root 2544 0.0 0.0 20388 188 ? S 18:47 0:00 daemon --name=test_daemon --respawn -o /tmp/test.log -- /root/test/a.out
root 2545 0.0 0.0 4508 740 ? S 18:47 0:00 /root/test/a.out
此时查看/tmp/test.log会看到有相关的输出
root@lan-dev-215:~/test# tail /tmp/test.log
hello 7
hello 8
hello 9
hello 10
hello 11
hello 12
杀掉a.out,看下是否还有
root@lan-dev-215:~/test# kill 2545
root@lan-dev-215:~/test# ps aux | grep a.out
root 2544 0.0 0.0 20388 1764 ? S 18:47 0:00 daemon --name=test_daemon --respawn -o /tmp/test.log -- /root/test/a.out
root 2549 0.0 0.0 4508 744 ? S 18:47 0:00 /root/test/a.out
可以看到a.out重启了,分配了一个新的pid,而且tty是?
除了使用daemon命令,在C里面也可以直接调用daemon,让a.out变成守护进程。我们把代码改下,增加一行daemon调用:
#include <stdio.h>
main(void)
{
daemon(0,0);
int d = 1;
while(1){
printf("hello %d \n",d);
fflush(stdout);
sleep(1);
d += 1;
};
return 0;
}
此时重新gcc编译一下,运行a.out,可以看到该进程变成了守护进程。
daemon是怎么实现的
看下daemon的主函数 https://github.com/lattera/glibc/blob/master/misc/daemon.c
直接注释着来看吧。
daemon (int nochdir, int noclose)
{
int fd;
switch (__fork()) {
case -1:
return (-1);
case 0:
break;
default:
// fork成功后,父进程正常退出,子进程托孤,继续往下走
_exit(0);
}
if (__setsid() == -1)
/*
调用setsid,将自己改成一个新的sid,即变成一组新的会话,不受到原sid的影响。
比如在terminal上运行普通程序时,sid是shell的,此时该程序受到terminal的影响
这里调用setsid后,sid是新的了,不再依赖原sid
*/
return (-1);
// 后面是修改程序运行路径,标准输入输出等
if (!nochdir)
(void)__chdir("/");
if (!noclose) {
struct stat64 st;
if ((fd = __open_nocancel(_PATH_DEVNULL, O_RDWR, 0)) != -1
&& (__builtin_expect (__fxstat64 (_STAT_VER, fd, &st), 0)
== 0)) {
if (__builtin_expect (S_ISCHR (st.st_mode), 1) != 0
#if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
&& (st.st_rdev
== makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR))
#endif
) {
(void)__dup2(fd, STDIN_FILENO);
(void)__dup2(fd, STDOUT_FILENO);
(void)__dup2(fd, STDERR_FILENO);
if (fd > 2)
(void)__close (fd);
} else {
/* We must set an errno value since no
function call actually failed. */
__close_nocancel_nostatus (fd);
__set_errno (ENODEV);
return -1;
}
} else {
__close_nocancel_nostatus (fd);
return -1;
}
}
return (0);
}