Loading... ### Linux:守护进程(进程组、会话和守护进程) 守护进程(Daemon)是 Linux 系统中一种长期运行的后台进程,通常用于执行系统级别的任务或服务。理解守护进程涉及进程组、会话及其与其他进程的关系。本文将详细介绍这些概念及其在 Linux 中的应用。 #### 一、进程组(Process Group) 进程组是一个或多个进程的集合,用于信号传递和终端输入输出控制。进程组中的每个进程都有一个相同的进程组 ID(PGID),PGID 等于进程组组长的进程 ID(PID)。 ##### 1. 创建进程组 当一个进程创建新进程时,默认情况下新进程继承其父进程的 PGID。可以通过调用 `setpgid` 函数来改变进程的 PGID。 ```c #include <unistd.h> #include <stdio.h> int main() { pid_t pid = fork(); if (pid == 0) { // 子进程 setpgid(0, 0); // 创建新的进程组 printf("Child process PGID: %d\n", getpgid(0)); } else { // 父进程 printf("Parent process PGID: %d\n", getpgid(0)); } return 0; } ``` ##### 2. 查看进程组 可以使用 `ps` 命令查看进程的 PGID: ```sh ps -o pid,pgid,cmd ``` #### 二、会话(Session) 会话是一个或多个进程组的集合。会话由一个会话首领进程创建,该进程成为会话的领导者,并且它的 PID 就是会话 ID(SID)。会话首领进程可以通过调用 `setsid` 函数创建一个新的会话。 ##### 1. 创建会话 创建一个新的会话,将当前进程变为会话领导者: ```c #include <unistd.h> #include <stdio.h> int main() { pid_t sid = setsid(); // 创建新的会话 if (sid == -1) { perror("setsid"); return 1; } printf("Session ID: %d\n", sid); return 0; } ``` ##### 2. 查看会话 可以使用 `ps` 命令查看进程的 SID: ```sh ps -o pid,sid,cmd ``` #### 三、守护进程(Daemon) 守护进程是一种在后台运行的进程,通常由系统启动脚本或其他服务管理工具启动。守护进程脱离控制终端,独立于用户的会话。 ##### 1. 创建守护进程 创建守护进程的一般步骤包括: 1. **创建子进程,终止父进程**:确保守护进程不是会话领导者,防止它重新打开控制终端。 2. **创建新的会话**:使守护进程成为新会话的领导者。 3. **改变工作目录**:通常将工作目录更改为根目录,以防止锁定任何挂载的文件系统。 4. **重设文件权限掩码**:防止继承父进程的文件权限。 5. **关闭文件描述符**:关闭继承的文件描述符。 下面是一个创建守护进程的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> void daemonize() { pid_t pid; // 创建子进程 pid = fork(); if (pid < 0) { exit(EXIT_FAILURE); } if (pid > 0) { exit(EXIT_SUCCESS); // 父进程退出 } // 创建新的会话 if (setsid() < 0) { exit(EXIT_FAILURE); } // 捕获、忽略 SIGHUP 信号 signal(SIGHUP, SIG_IGN); // 创建新子进程,终止父进程,防止重新获得控制终端 pid = fork(); if (pid < 0) { exit(EXIT_FAILURE); } if (pid > 0) { exit(EXIT_SUCCESS); } // 改变工作目录 if (chdir("/") < 0) { exit(EXIT_FAILURE); } // 重设文件权限掩码 umask(0); // 关闭文件描述符 close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); } int main() { daemonize(); // 守护进程的主循环 while (1) { // 执行后台任务 sleep(30); // 示例:每隔30秒执行一次任务 } return EXIT_SUCCESS; } ``` #### 四、管理守护进程 ##### 1. 使用 `systemd` 现代 Linux 系统通常使用 `systemd` 管理守护进程。可以创建一个 `systemd` 服务文件来管理守护进程。 创建一个示例服务文件 `/etc/systemd/system/mydaemon.service`: ```ini [Unit] Description=My Daemon Service [Service] ExecStart=/usr/local/bin/mydaemon Restart=always User=nobody Group=nobody [Install] WantedBy=multi-user.target ``` 然后启用并启动服务: ```sh sudo systemctl enable mydaemon sudo systemctl start mydaemon ``` ##### 2. 使用 `init.d` 在旧版 Linux 系统中,可以使用 `init.d` 脚本管理守护进程。创建一个示例脚本 `/etc/init.d/mydaemon`: ```sh #!/bin/sh ### BEGIN INIT INFO # Provides: mydaemon # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: My Daemon Service ### END INIT INFO case "$1" in start) echo "Starting mydaemon" /usr/local/bin/mydaemon & ;; stop) echo "Stopping mydaemon" pkill mydaemon ;; restart) $0 stop $0 start ;; *) echo "Usage: $0 {start|stop|restart}" exit 1 esac exit 0 ``` 然后启用并启动服务: ```sh sudo chmod +x /etc/init.d/mydaemon sudo update-rc.d mydaemon defaults sudo service mydaemon start ``` #### 五、思维导图 ```plaintext Linux 守护进程 │ ├── 进程组 │ ├── 定义:进程集合 │ ├── 创建:fork + setpgid │ ├── 查看:ps -o pid,pgid,cmd │ ├── 会话 │ ├── 定义:进程组集合 │ ├── 创建:setsid │ ├── 查看:ps -o pid,sid,cmd │ ├── 守护进程 │ ├── 定义:后台长期运行进程 │ ├── 创建步骤 │ │ ├── 创建子进程,终止父进程 │ │ ├── 创建新会话 │ │ ├── 改变工作目录 │ │ ├── 重设文件权限掩码 │ │ └── 关闭文件描述符 │ └── 示例代码 │ └── 管理守护进程 ├── 使用 systemd │ ├── 服务文件示例 │ └── 启用和启动服务 └── 使用 init.d ├── 脚本示例 └── 启用和启动服务 ``` #### 六、总结 守护进程在 Linux 系统中扮演着重要角色,通过后台执行关键任务和服务,确保系统的稳定运行。理解进程组和会话的概念,是正确创建和管理守护进程的基础。使用现代的 `systemd` 或传统的 `init.d` 方法,可以有效地管理守护进程,提升系统的可靠性和可维护性。希望本文能帮助读者深入理解并掌握 Linux 守护进程的相关知识。 最后修改:2024 年 08 月 08 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 如果觉得我的文章对你有用,请随意赞赏