linux——守护进程

一、核心铺垫:先懂 3 个层级关系

Linux 进程三层包裹:会话 (Session) → 进程组 (Process Group) → 进程 (Process)

  • 一个会话包含多个进程组
  • 一个进程组包含多个进程
  • 终端登录 = 打开一个会话,所有命令 / 程序都挂在这个会话下

一、进程组(Process Group)

1. 什么是进程组?

一组有关联的进程打包成一个团队 ,方便统一管理(发信号、结束、调度)。比如:一条管道命令 ls | grep txt,两个进程默认在同一个进程组。

2. 进程组长(组长进程)

  • 创建这个进程组的第一个进程,就是组长
  • 规矩:进程组 ID = 组长的 PID
  • 举例:组长 PID=1000 → 整个进程组 ID=1000

3. 关键特性

  1. 组长可以创建子进程,子进程自动归入当前进程组
  2. 只要组里还有一个进程,进程组就不会销毁
  3. 终端操作(Ctrl+C / Ctrl+Z)是发给整个进程组,不是单个进程

4. 常用函数

  • getpgid(pid):获取某个进程的进程组 ID
  • setpgid(pid, pgid):修改进程组(把某个进程加入指定组)

通俗总结

进程组 = 一个班级组长 = 班长全班 ID = 班长学号老师发指令(信号)→ 全班都收到

二、会话(Session)

1. 什么是会话?

会话是最高层级 ,绑定一个控制终端(你打开的黑框终端)。:你登录终端→创建一个会话→所有执行的程序都挂在这个会话里。

2. 会话核心特点

  1. 一个会话对应一个终端(桌面终端、SSH 远程终端)
  2. 终端关闭 / 用户注销 → 会话下所有前台进程全部被杀掉
  3. 守护进程要脱离终端,本质就是脱离原会话

3. 创建新会话的硬性规则(超级重要)

调用 setsid() 创建新会话,必须满足:

  1. 当前进程不能是原进程组的组长(核心!)
  2. 执行完 setsid() 后:
    • 该进程变成新会话的会长
    • 自动成为新进程组的组长
    • 彻底脱离原来的控制终端(再也不收终端影响)
    • 原终端关闭、注销登录,完全跟它没关系

4. 为什么要先 fork、父进程退出?

  • 原本进程是组长,没法 setsid()
  • fork 出子进程 → 子进程不是组长
  • 父进程退出,子进程独立 → 子进程顺利新建会话

5. 常用 API

  1. getsid(pid):获取进程所属会话 ID
  2. setsid():创建新会话(无参数,调用者自己进新会话)

通俗总结

会话 = 整个年级终端 = 年级教室关教室(关终端)→ 年级里所有学生(进程)全赶走守护进程 = 转学出去,脱离教室,不关不停

三、守护进程(Daemon)

1. 什么是守护进程?

Linux 后台永久运行的服务进程,英文名 Daemon,大部分系统服务、后台程序都是它。

2. 五大核心特点(扩展完整版)

  1. 全程后台运行,不占用终端
  2. 彻底脱离控制终端:关黑框、注销 SSH、退出登录都不影响
  3. 周期性循环工作 / 常驻监听(日志、定时、端口监听)
  4. 不会被终端信号杀死(Ctrl+C、关闭终端无效)
  5. 官方规范:服务名一般以 d 结尾(httpd、sshd、mysqld)
  6. 不打印杂乱输出到终端(要打就打日志文件)

3. 为什么普通程序不能当守护进程?

普通程序挂在终端会话下:

  • 关掉终端 → SIGHUP 信号杀掉所有进程
  • 守护进程必须:脱离会话→脱离进程组→脱离终端

四、创建守护进程 标准 7 步模型

步骤 1:fork () 创建子进程,父进程直接 exit

原因:

  • 原进程是进程组长,没法新建会话
  • 子进程是普通进程,满足 setsid() 条件效果:程序后台化,脱离前台终端

步骤 2:子进程调用 setsid () 创建全新会话

三大质变:

  1. 子进程 = 新会话首领
  2. 子进程 = 新进程组组长
  3. 彻底切断与原终端的所有关联(关键点)

步骤 3:再次 fork ()(可选高阶加固)

防止后期进程重新打开终端,彻底杜绝控端绑定。

步骤 4:chdir ("/") 修改工作目录

原因:

  • 原来目录如果被卸载、删除、U 盘拔出,程序会崩
  • 改成根目录 /,绝对安全常驻

步骤 5:umask (0) 重置文件权限掩码

原因:

  • 默认掩码可能限制日志、文件创建权限
  • 清零后,守护进程创建文件权限完全可控

步骤 6:关闭所有无用文件描述符(0/1/2)

  • 0:标准输入(键盘)
  • 1:标准输出(终端打印)
  • 2:标准错误(终端报错)原因:守护进程不用终端 IO,留着会占用资源、乱输出。规范做法:把 0/1/2 重定向到 /dev/null(黑洞)

步骤 7:写核心业务逻辑(while (1) 常驻循环)

  • 定时任务
  • 监听端口
  • 写日志
  • 巡检、同步数据

五、三者层级关系一张图看懂

plaintext

复制代码
终端会话(Session)
    ├─ 进程组1(前台命令)
    │     ├ 进程1(组长)
    │     └ 子进程
    ├─ 进程组2(后台普通程序)
    └─ 被剥离:守护进程
          独立会话 → 独立进程组 → 无终端绑定 → 永久后台运行

六、总结

  1. 进程组:一组关联进程,有组长,组 ID = 组长 PID

  2. 会话:包裹多个进程组,绑定终端,关终端杀全组进程

  3. setsid():非组长才能调用,创建新会话、脱离终端

  4. 守护进程本质:脱离终端 + 脱离原会话 + 常驻后台 + 独立运行

  5. 创建流程口诀:fork 退出建会话,改目录清掩码,关描述常驻干活

    #include<stdio.h>
    #include<unistd.h>
    #include<stdlib.h>
    #include<sys/stat.h>

    void daemon_create()
    {
    pid_t pid = fork();
    if(pid > 0) exit(0); // 父进程退出

    复制代码
     setsid();              // 子进程建新会话
    
     chdir("/");            // 切换根目录
     umask(0);              // 清空权限掩码
    
     // 关闭标准IO
     close(0);
     close(1);
     close(2);

    }

    int main()
    {
    daemon_create();

    复制代码
     // 核心常驻业务
     while(1)
     {
         // 定时任务、日志、监听
         sleep(3);
     }
     return 0;

    }

相关推荐
kvo7f2JTy2 小时前
吃透Linux/C++系统编程:文件与I/O操作从入门到避坑
java·linux·c++
Vect__2 小时前
深刻理解虚拟内存机制
linux
maosheng11462 小时前
Linux的第二次作业
linux·运维·服务器
maosheng11462 小时前
Linux
linux·运维·服务器
sR916Mecz3 小时前
Linux 服务器磁盘扩容与目录迁移:rsync + bind mount 实现服务无感迁移(无需修改配置)
java·linux·服务器
扑火的小飞蛾3 小时前
Windows 10 与 Kali Linux SSH 免密互信配置指南
linux·windows·ssh
0xDevNull3 小时前
Linux服务器日志查看完全指南
linux·运维·服务器
songx_994 小时前
Linux基础1
linux·运维·服务器
蓝天居士4 小时前
cpio命令详解(3)
linux·cpio