Linux守护进程(Daemon)完全指南:从原理到实战-CSDN博客


1. 回顾:守护进程做了什么?

我们之前实现的 Daemon() 函数,把一个普通的前台程序变成了:

  • 脱离终端setsid() + fork() 使其不再受 Ctrl+C、终端关闭影响

  • 重定位工作目录chdir("/") 防止占用可卸载文件系统

  • 重定向标准 IO:所有输出输入都指向 /dev/null,避免干扰

这样一来,我们的 ServerNetcald 程序就可以像一个真正的系统服务一样后台常驻。

但有了守护进程化的程序,我们还需要一套部署规范,让服务可以方便地安装、启动、停止、查看日志。


2. 部署前的准备:Makefile 解析

提供的 Makefile 非常简短,但包含了很多部署思想。我们先逐行看:

.PHONY: all
all: ServerNetcald client_netcal

ServerNetcald: main.cc
	g++ -o $@ $^ -std=c++17 -ljsoncpp

client_netcal: TcpClient.cc
	g++ -o $@ $^ -std=c++17 -ljsoncpp

  • all 是默认目标,负责编译服务器和客户端。

  • 使用 -ljsoncpp 链接 JSON 库,说明通信协议可能基于 JSON。

  • $@ 和 $^ 是自动变量,分别代表目标文件和依赖文件。

部署的精髓在下面的 output 目标

.PHONY: output
output:
	@mkdir output
	@mkdir -p output/bin
	@mkdir -p output/conf
	@mkdir -p output/log
	@cp ServerNetcald output/bin
	@cp client_netcal output/bin
	@cp test.conf output/conf
	@tar czf output.tgz output

这个目标定义了标准的交付包结构


3. 标准化输出目录结构

执行 make output 后,会生成以下目录树:

为什么要这样划分?

目录 用途
bin/ 存放可执行文件,便于加入 PATH 或直接运行
conf/ 配置文件与代码分离,修改配置无需重新编译
log/ 运行日志存放位置,方便轮转和监控

这种布局是 Linux 服务部署的常见惯例(类似于 /usr/local/服务名 下的结构)。将配置和二进制分开,也符合十二要素应用中“配置与代码分离”的原则。

最后一条命令 tar czf output.tgz output 将整个目录打包成 output.tgz,这就是可交付的部署包


4. 打包与分发

执行:

make clean      # 清理旧构建
make all        # 编译程序
make output     # 创建目录结构并打包

你会得到 output.tgz 文件。将它拷贝到目标服务器,解压后就能运行:

tar xzf output.tgz
cd output

这种发布方式的好处:

  • 不依赖源码环境,只需目标机器有运行时库(如 libjsoncpp

  • 目录结构固定,便于写启动脚本(如 systemd service)

  • 日志和配置外置,运行时可以动态修改


5. 如何在生产环境运行守护进程

虽然我们的 ServerNetcald 内部调用了 Daemon(false, false) 把自己变成守护进程但直接运行仍然会立即返回(因为父进程退出)。那么如何启动、停止、查看状态呢?

5.1 手动启动

cd output/bin
./ServerNetcald 8080

因为程序会自行 daemonize,执行后 shell 会立即返回(实际上控制权已经交还给终端)。你可以用 ps 验证:

ps aux | grep ServerNetcald

项目部署不是简单的"复制文件",而是一个从源码到系统服务的完整工程化流程

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐