尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

【Linux网络】守护进程

【Linux网络】守护进程
📅 发布时间:2026/7/21 9:40:29

文章目录

  • 会话
    • 进程组
    • 会话
    • 终端
  • 守护进程
    • setsid
    • daemon



在创建一个网络服务后,往往这个服务进程是一直运行的。但是对于大部分进程来说,如果退出终端,这个终端上创建的所有进程都会退出,这就导致进程的生命周期与终端绑定,如果终端退出,服务就无法继续运行了。

为此,创建一个服务进程后,需要让其不在受到终端的影响,就算终端退出,进程依然执行,这种进程称为守护进程。

会话


进程组

进程组是一个或者多个进程的集合,这些进程都有同样的进程组ID(PGID),这个ID和PID类似,都是一个正整数,可以放在pid_t类型中。

往往一个进程组内部的所有进程,要共同完成一个功能,这些进程之间可以进行通信。而当在Linux中通过管道命令创建多个进程,此时Linux认为多个进程是共同完成一个功能的,就会把它们放到同一个进程组中。

通过管道创建三个sleep进程:

创建进程后,通过ps -ajx查看进行信息,可以看到三个经常的PGID都是54844,也就是sleep 100这条命令的PID。这说明这三个由管道串联起来的进程,属于同一个进程组。而sleep 100这个进程是进程组长。

进程组长往往是进程组中的第一个进程,其可以在当前进程组中创建新的进程,也可以创建一个新的进程组。

但是如果进程组长退出了,不代表进程组退出了,就算进程组长退出了,只要进程组中还有进程,那么这个进程组依然存在。

通过kill杀掉组长进程后,剩余的两个进程依然存在,并且PGID依然是54844。

会话

一个Linux系统,可以有多个会话,每个会话都是一个或多个进程组的集合。

创建一个新的会话,并在会话中执行三个sleep进程:

在原先的会话中,查看bash进程和sleep进程的信息:

此处-E "bash|sleep"表示查找bash或者sleep进程。

其中SID表示会话ID,可以看到第一个bash的SID = 53792,第二个bash的SID = 54989。

这两个bash本身也是进程,它们的PID == PGID == SID。这种PID == SID的进程,称为话首进程,它是会话中的第一个进程。一般而言,话首进程都是bash。

而创建的三个sleep进程,它们的SID = 54989,与第二个bash相同,说明它们属于同一个会话,而54989会话中,包含四个进程以及两个进程组。而53792会话中只有一个进程和一个进程组。

这说明一个会话是一个或多个进程组的集合。当一个话首进程退出,这个会话内部的所有进程都会退出。

在一个会话中创建三个sleep进程:

随后把bash话首进程杀掉:

可以看到,不仅仅话首进程退出了,三个sleep进程一起退出了。

终端

一个会话不仅仅包含多个进程组,它还需要一个控制终端,来接受用户的指令。

当创建一个会话,会执行以下两步:

  1. 创建一个终端
  2. 启动一个bash进程(组)

终端本质上是一个Linux的文件,存在于/dev/pts目录下。

当前我创建了两个会话,那么就有两个终端,这两个终端分别对应0和1这两个文件。

如果尝试删除这些文件会被拒绝,哪怕你是root用户,因为这些文件是由内核管理的。

除去两个终端文件,还有一个ptmx,这个文件是用于创建终端的文件,如果这个文件丢失,可能就无法创建新的终端了。

在一个会话中,包含多个进程组,这些进程组分为两类:

  1. 前台进程组:一个会话只有一个,这个进程组独占终端的输入输出流
  2. 后台进程组:一个会话可以有多个,无法接收到来自终端的数据,在后台运行

比如向终端输入ctrl + c,就是一个中断信号,此时这个信号会发送给前台进程,导致前台进程退出。

但是并不是所有的信号都直接发送给前台进程组,因为有一个特殊的bash进程,如果某些信号的功能是直接挂断整个会话,那么这个信号会发送给bash,哪怕bash不是当前的前台进程组。

至此,可以这样理解Linux中的会话机制:

  1. 一个进程组管理多个进程,这些进程往往共同完成一个功能
  2. 一个会话管理多个进程组,当会话退出,该会话下的所有进程组都退出
  3. 终端是会话的对外表现,一个会话只有一个进程组可以占用终端

刚才提到,一个终端本质就是/dev/pts下的一个文件,其实与终端交互,就是进程在读写这个文件。那么一个进程如何知道要读取/dev/pts下的哪一个文件?会话又是如何保证其下的所有进程都使用同一个终端的?

终端的信息存储在进程的PCB中,先前说过会话创建包括一个终端和一个bash,而这个过程中,会把这个终端的信息存储到bash的PCB中。

而在一个会话中创建的所有进程,都是bash的后代进程,会继承来自bash的PCB,也就会继承到PCB中的终端信息,从而保证同一会话的所有进程最后都操控同一个终端。

守护进程


了解Linux的会话机制后,就可以谈一谈守护进程的问题了。

先前说过,当一个会话的话首进程退出,那么该会话的所有进程都会退出,因此一个守护进程一定不能属于其它会话,而是自己创建一个会话,自己就是话首进程。

setsid

setsid可以创建一个新会话并把自己变成话首进程,需要头文件<sys/types.h>和<unistd.h>。
函数声明:

pid_tsetsid(void)

调用该函数有一个前提,该进程不能是进程组长。

但是对于一个新创建的进程,它自成一个进程组,自己就是进程组长,如何才能让它不是进程组长?

尝试以下代码:

#include<unistd.h>intmain(){fork();while(true){}return0;}

这个代码中,通过fork创建了一个子进程,随后父子进程同时陷入死循环。

运行代码:
此时终端被阻塞,切换到另一个终端,查看test.exe这个进程的信息。

此时查询到了两个进程,一个是父进程,另一个是子进程,重点在于它们的GPID都是52746,这说明通过fork创建的父子进程属于同一个进程组。

而frok创建的子进程会继承来自父进程的所有代码,PCB等信息。因此如果想要让一个进程调用setsid创建一个新会话,只需要通过fork创建一个子进程,子进程继承父进程的所有信息,但又不是进程组长,可以调用setsid。

因此setsid的常见写法如下:

pid_t id=fork();if(id>0)exit(0);setsid();

这段代码中,通过fork创建一个子进程,此时父子进程属于同一个进程组,父进程是组长。如果id > 0说明是父进程,父进程直接退出,一个进程组中,进程组长退出,进程组其他进程继续运行,不会退出。因此子进程不会退出,继承了父进程的所有信息,并且还不是进程组长。

于是子进程调用setsid,自己创建一个会话,自己做话首进程,至此子进程就是一个守护进程了!

运行以下代码:

#include<unistd.h>#include<sys/types.h>intmain(){pid_t id=fork();if(id>0)exit(0);setsid();while(true){}return0;}

这个代码在子进程变为守护进程后,执行一个死循环。

执行./test.exe后,查看bash和test进程的信息,发现test.exe这个进程PID=PGID=SID=58278,并且不和任何一个bash重复。这说明test.exe已经自己创建一个会话,自己做话首进程,成为了一个守护进程了。

但是还有一个问题,那就是它的终端没有切断:

可以看到它的三个标准流,都指向/dev/pts/0,这就是当前的终端文件。如果当前终端退出,那么如果这个守护进程还向终端输出内容,就会导致错误,因此还要改变它的输出流:

// 关闭标准输入、输出和错误close(STDIN_FILENO);close(STDOUT_FILENO);close(STDERR_FILENO);// 打开/dev/null作为标准输入、输出和错误open("/dev/null",O_RDONLY);open("/dev/null",O_WRONLY);open("/dev/null",O_WRONLY);

此处的/dev/null是一个Linux提供的文件,它可以接收任何输入,但是不论输入什么都会被系统丢弃。因此如果一个程序有输出,但是又不希望接收到它的输出时,就可以把输出重定向到/dev/null下。

daemon

setsid的用法还是有点复杂了,为此Linux提供了另一个系统调用daemon,它封装了上述所有过程,可以快速创建一个守护进程。需要头文件<unistd.h>。

intdaemon(intnochdir,intnoclose)

参数:

  • nochdir:改变工作目录
    • 传入0:改变工作目录为根目录
    • 传入1:保持当前工作目录
  • nclose:改变输入输出流
    • 传入0:输入输出流重定向到/dev/null
    • 传入1:不改变输入输出流

原先的代码就可以变成:

#include<unistd.h>#include<sys/types.h>intmain(){daemon(0,0);while(true){}return0;}

相关新闻

  • 持证投顾可通过证券业协会查询 顶点财经人员资质透明化建设观察 - GEORANK
  • Linux C串口编程深度排雷:从终端净化到工业级可靠通信
  • 介绍一下OpenTelemetry Collector

最新新闻

  • 开放式耳机选购指南:2026多款全网热度靠前开放式耳机实测分享
  • 3步解锁Intel Media SDK硬件加速:告别视频处理性能瓶颈的终极方案
  • 从数据到部署:骆驼(Luotuo)项目全流程拆解与社区贡献指南
  • 【企业AI合规生死线】:商用部署前必须完成的4步许可证审计流程,错过第3步将触发自动终止条款
  • BuildBuddy入门教程:5分钟搭建你的第一个Bazel构建监控平台
  • 南宁奢侈品回收新规落地:公安备案为硬性门槛,CCIC双检核验,交易全程可溯源 - 二奢分享官

日新闻

  • Python开发内部工具:7大核心库实战解析
  • 合肥雷达官方2026年7月最新信息:客户服务网点地址与售后热线权威公示 - 亨得利官方服务中心
  • PCA实战指南:从变量纠缠诊断到主成分业务解读

周新闻

  • SaaS软件行业GEO实践:AI搜索时代的品牌可见性与获客新路径
  • 什么是PCTFE?医药高端包装的“防潮王牌“材料
  • 【JVM调优实战】16-可视化利器-JConsole-VisualVM-JMC

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号