在Linux下有守护进程的概念,即程序执行后在后台运行。许多服务端程序都是守护进程,不需要在命令行进行交互。这种程序的行为在Windows下也是类似的。
首先我们观察一下在前台进行的程序在进程树中是什么样的。这里写了一个测试用的命令行程序rest.exe,它是作用就是死循环模拟一些需要长时间运行的服务,当在命令行执行该程序时,我们在procExp.exe中对其进行观察:
Microsoft Windows [版本 10.0.19041.208]
(c) 2020 Microsoft Corporation. 保留所有权利。
C:\Users\Administrator>cd /d d:\
d:\>rest.exe
在procExp.exe中,可以看到rest.exe进程之上还有一个conhost.exe父进程,其中conhost.exe是console host process的意思,是微软在win7之后引入的,起到安全隔离的作用。所有命令行程序都会启动一个conhost.exe的进程作为父进程。此时rest.exe进程是在前台运行的。
如果想让rest.exe进程在后台运行,此时可以调用 start b 让其在后台运行:
start b rest.exe
此时可以看到 rest.exe 进程已经在后台进行了,不再占用命令行的位置,可以在命令行中执行其它命令,比如 ping 命令。我们再在后台看下进程树有什么变化:
可以看到 rest.exe 的进程仍然是 conhost.exe,如果此时把 cmd.exe 的窗口叉掉,cmd.exe 的所有子进程都会死掉,包括在后台运行的 rest.exe 进程。此时使用 start b 启动的程序还不是守护进程,要想让进程变成守护进程还需要额外多做一步。在讲这一步之前,我们需要了解Linux下的守护进程是怎么写的。
Linux下的守护进程是剥离进程组的会话,如果想让一个进程变成守护进程,要在它的子进程中把父进程干掉。一般标准的守护进程的程序是这样写的:
void daemon() {
// fork 出一个子进程。
pid_t pid = fork();
// fork 失败。
if( pid == -1) {
perror("fork");
exit(1);
}
// 退出父进程。
if(pid) {
exit(0);
}
// 创建新会话。
// 该子进程会成为新的会话和进程组的组长。
if(setsid() == -1) {
perror("setsid");
exit(1);
}
// 再 fork 一次,新的子进程不再是会话组长。
pid = fork();
if( pid == -1) {
perror("fork");
exit(1);
}
if(pid) {
exit(0);
}
// 关掉从父进程继承的文件描述符。
int max_fd = sysconf(_SC_OPEN_MAX);
for(int i = 0; i < max_fd; ++i) {
close(i);
}
// 重定向文件描述符 0, 1, 2 到 dev/null
open("/dev/null", O_RDWR);
dup(0);
dup(0);
// 设置文件创建权限掩码,不希望被父进程的掩码限制。
umask(0);
// 将当前工作目录设置为系统根目录。
chdir("/");}
当主动结束掉父进程,那么守护进程的父进程就会继承1号进程作为父进程。而在Windows下命令行下的程序的父进程是conhost.exe,此时如果把conhost.exe进程结束掉,那么其下的子进程就会变成守护进程,即后台进程。
tasklist | findstr conhost.exe
taskkill /im conhost.exe /f
执行完上面的杀进程的命令后,所有 conhost.exe 进程都被杀掉了,同时消失掉的还是命令行窗口。此时已经看不到命令行程序,但在任务管理器中可以看到,我们还是在procExp.exe中查看,因为可以看到进程树。
从 procExp.exe 中还可以看到 rest.exe 和 ping.exe 程序还在运行,命令行窗口已经找不到了。以上方法比较暴力,如果试过在 procExp.exe 中结束掉 conhost.exe 进程,可以看到 rest.exe 进程会成为独立的进程,没有父进程,此时也是处于后台在运行。以上通过结束 conhost.exe 的方式比较粗暴,还有一种方式可以让命令行程序成为后台进程,也是通过结束父进程的方式,是以脚本方式运行的,脚本如下:
@ECHO OFF
%1 start mshta vbscript:createobject("wscript.shell").run("""%~0"" ::",0)(window.close)&&exit
start /b d:\rest.exe
把命令包一层,调用vbscript杀父进程。把脚本保存为 test.bat,执行后 rest.exe 变成了独立的进程,同时 conhost.exe 进程也保留了下来。如果在系统中有很多 conhost.exe 进程说明也有其它后台服务是这么干的。
参考:
https://cloud.tencent.com/developer/article/1635805
https://blog.csdn.net/surfirst/article/details/113123446
全文完。
如果转发本文,文末务必注明:“转自微信公众号:生有可恋”。