"忍耐的灵魂啊,安静地运转吧~"
我们先来看看这个场景。这是一个常见的基于TCP套接字的网络服务器,服务端接收客户端发送的消息,收到后并向echo回响给客户端。
对于Linux而言,终端只能有一个前台进程,这也是为什么当我们在服务端一侧启动服务时,继续输入诸如ls\pwd\which等命令时,bash(shell)没有作任何响应。
现在我们将服务端的窗口关闭后,可以发现的是,客户端就自动退出了。
这是为什么呢?上述图片描述了什么呢? SID又是什么呢??我们又该如何解决这个问题呢,让我们即便会话窗口退出,也不影响服务器的运行?
——前言
回答上面的问题并不难,我们使用的Xshell向远端建立链接时,会为用户自动生成一个名为会话的窗口,而SID指的就是会话ID。可以到,图示的打开的三个会话窗口,都具有不同的会话ID。
我们来看看下面一段代码的例子,使用匿名管道没有别的特殊用意。
sleep 10000 | sleep 20000 | sleeep 30000
启动程序后面加"&",意味着让该程序启动后,运行在后台。此时我们用jobs可以查看这个工作在后台的进程。
当我们将上述的三个进程在后台进行运行时,这三个用匿名管道连接起来的进程看似毫不相干,但它们都同属于一个进程组(PGID)!
这个代码里创建的所有进程都在"协同"完成一件事情——休眠(sleep)。
为此,我们把正在执行的一个或多个相关的进程被称为"作业"。
我们输入jobs命令,可以查看后台进程的任务。我们可以通过 fg\bg 命令来回将一个作业进行前、后台状态的切换。
对!你上面说的我都理解,当使用Xshell进行远端登录时,会为不同的窗口创建不同的session_Id,而一旦这个会话窗口关闭,其实也就意味着该窗口内运行着的前、后台也会进程关闭。但你还是没有解决服务器不依赖会话的运行的问题。
守护进程(也叫做精灵进程)deamon,是生存期较长的一种进程,它们常常在系统自举时启动,仅仅在系统关闭时终止。因为它们没有终端,也就意味着它们是运行在后台的。
在Linux中存在很多守护进程,它们执行事务活动。
我们使用命令:
-a: 显示由其他用户所拥有的进程状态
-x: 显示没有控制终端的进程状态
-j: 显示与作业有关的信息
ps -axj
其中有意义的列标为,父进程ID,进程ID,进程组ID,会话ID,终端名称,终端进组ID,用户ID,命令字符串。
TPGID为-1的为守护进程。
在linux系统中,每个系统与用户进行交流的界面成为终端,每一个从此终端开始运行的进程都会依附于这个终端,这个终端被称为这些进程的控制终端。当用户断开连接,会话关闭,终端关闭后,该终端内的进程也会随之关闭。
然而,守护进程却可以突破这种限制,因为守护进程是没有终端的。它脱离终端的目的是为了避免进程在运行的过程中的信息,并且进程也不会被任何终端所产生的终端信息所打断。
实现:
// #pragma once
#include
#include
#include
#include
#include
#include
#include
#define DAEMON_FILE "daemonlog.txt"
void daemonSelf(const char* currPath = NULL)
{
// 1.创建子进程
if(fork() > 0) exit(0);
// 2.另起会话 本质就是一个孤儿进程
pid_t id = setsid();
// 断死不会错误
assert(id != -1);
// 3.关闭终端
// 输出信息到daemonlog.txt
int fd = open(DAEMON_FILE,O_RDWR);
if(fd >= 0)
{
dup2(fd,0);
dup2(fd,1);
dup2(fd,2);
close(fd);
}
else
{
close(0);
close(1);
close(2);
}
char buffer[] = "dup2重定向完毕\n";
write(fd,buffer,sizeof(buffer));
// 4.更改工作路径
if(currPath) chdir(currPath);
// 5.文件掩码
umask(0);
char buffer2[] = "守护进程创建完成\n";
write(fd,buffer2,sizeof(buffer2));
}
int main()
{
printf("开始创建\n");
daemonSelf();
return 0;
}
此时我们在命令行运行该程序,通过ps 查询该进程的 TPGID 为-1,验证是为守护进程。
我们再将左端的(创建端)session窗口关闭后重新链接,可以得出,此进程自此不受用户远程登录、断开连接的影响,自成会话。
但这并不意味着这个进程就可以为所欲为了,我们也可以在命令行终端输入kill -9 发送信号"杀死"该进程。
守护进程常常用作服务器进程,一般而言服务器是等待客户进程与其进行联系的一个进程。守护进程在大多数Linux中是一直运行的,因为守护进程没有终端,我们可以选择将进程运行信息通过文件打印出来。