🔥作者简介: 一个平凡而乐于分享的小比特,中南民族大学通信工程专业研究生,研究方向无线联邦学习 🎬擅长领域:驱动开发,嵌入式软件开发,BSP开发 ❄️作者主页:一个平凡而乐于分享的小比特的个人主页 ✨收录专栏:c语言重要知识点总结,本专栏旨在总结C语言学习过程中的易错点,通过调试代码,分析原理,对重要知识点有更清晰的理解 欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖💖

在C语言中,Daemon(守护进程)是在后台运行的特殊进程,没有控制终端,独立于用户会话运行,通常用于提供系统级服务。它就像系统的"隐形守护者"。
特性 | Daemon进程 | 普通进程 |
|---|---|---|
控制终端 | 没有控制终端 | 有控制终端 |
运行位置 | 后台运行 | 前台/后台都可运行 |
会话领导 | 不是会话领导 | 通常是会话领导 |
文件描述符 | 通常关闭所有文件描述符 | 继承父进程的文件描述符 |
工作目录 | 通常切换到根目录 | 在当前目录运行 |
信号处理 | 忽略某些信号(如SIGHUP) | 默认信号处理 |
生命周期 | 系统启动到关闭 | 用户启动到结束 |
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
void create_daemon() {
pid_t pid;
// 1. 创建子进程,父进程退出
pid = fork();
if (pid < 0) {
perror("fork");
exit(1);
}
if (pid > 0) { // 父进程退出
exit(0);
}
// 2. 创建新会话,成为会话领导
if (setsid() < 0) {
perror("setsid");
exit(1);
}
// 3. 忽略SIGHUP信号
signal(SIGHUP, SIG_IGN);
// 4. 再次fork,确保不是会话领导
pid = fork();
if (pid < 0) {
perror("fork");
exit(1);
}
if (pid > 0) { // 父进程退出
exit(0);
}
// 5. 更改工作目录到根目录
chdir("/");
// 6. 设置文件权限掩码
umask(0);
// 7. 关闭所有文件描述符
for (int i = 0; i < getdtablesize(); i++) {
close(i);
}
// 8. 重定向标准I/O到/dev/null
int fd = open("/dev/null", O_RDWR);
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
close(fd);
}┌─────────────────────────────────────────┐
│ 用户空间 (User Space) │
├─────────────────────────────────────────┤
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Chrome │ │ VSCode │ │ SSH │ │ ← 用户进程
│ │ │ │ │ │ Client │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │
├─────────────────────────────────────────┤
│ 守护进程层 (Daemon Layer) │
├─────────────────────────────────────────┤
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐│
│ │cron │ │syslog│ │sshd │ │apache││ ← Daemon进程
│ │ │ │ │ │ │ │ ││
│ └──────┘ └──────┘ └──────┘ └──────┘│
└─────────────────────────────────────────┘// syslog_daemon.c - 系统日志守护进程示例
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
#include <signal.h>
#include <time.h>
#define LOG_FILE "/var/log/mydaemon.log"
void signal_handler(int sig) {
if (sig == SIGTERM) {
syslog(LOG_INFO, "Daemon收到终止信号,正在退出");
closelog();
exit(0);
}
}
void daemon_work() {
time_t now;
struct tm *tm_info;
while (1) {
time(&now);
tm_info = localtime(&now);
// 记录系统状态
syslog(LOG_INFO, "Daemon运行中 - 时间: %02d:%02d:%02d",
tm_info->tm_hour, tm_info->tm_min, tm_info->tm_sec);
// 模拟工作:检查日志文件大小
FILE *fp = fopen(LOG_FILE, "r");
if (fp) {
fseek(fp, 0, SEEK_END);
long size = ftell(fp);
fclose(fp);
if (size > 1024 * 1024) { // 超过1MB
syslog(LOG_WARNING, "日志文件过大: %ld bytes", size);
}
}
sleep(60); // 每分钟执行一次
}
}
int main() {
pid_t pid = fork();
if (pid < 0) {
perror("fork");
exit(1);
}
if (pid > 0) { // 父进程退出
exit(0);
}
// 子进程继续
setsid();
chdir("/");
umask(0);
// 设置信号处理
signal(SIGTERM, signal_handler);
signal(SIGHUP, SIG_IGN);
// 打开系统日志
openlog("mydaemon", LOG_PID, LOG_DAEMON);
syslog(LOG_INFO, "Daemon进程启动");
// 执行守护进程工作
daemon_work();
return 0;
}// network_daemon.c - 简单HTTP服务守护进程
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <syslog.h>
#define PORT 8080
#define MAX_CONN 10
void handle_client(int client_fd) {
char response[] = "HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"\r\n"
"Hello from Daemon Server!";
send(client_fd, response, strlen(response), 0);
close(client_fd);
}
void start_server_daemon() {
int server_fd, client_fd;
struct sockaddr_in address;
int addrlen = sizeof(address);
// 创建socket
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
syslog(LOG_ERR, "Socket创建失败");
exit(1);
}
// 设置socket选项
int opt = 1;
setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
// 绑定端口
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
syslog(LOG_ERR, "端口绑定失败");
exit(1);
}
// 监听连接
if (listen(server_fd, MAX_CONN) < 0) {
syslog(LOG_ERR, "监听失败");
exit(1);
}
syslog(LOG_INFO, "HTTP守护进程在端口 %d 启动", PORT);
// 主循环
while (1) {
client_fd = accept(server_fd, (struct sockaddr *)&address,
(socklen_t*)&addrlen);
if (client_fd < 0) {
syslog(LOG_WARNING, "接受连接失败");
continue;
}
syslog(LOG_INFO, "接收到新的客户端连接");
handle_client(client_fd);
}
}// task_scheduler.c - 定时任务调度守护进程
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
#include <time.h>
#include <dirent.h>
typedef struct {
time_t last_run;
int interval; // 执行间隔(秒)
void (*task_func)(void);
char *task_name;
} ScheduledTask;
void cleanup_temp_files() {
syslog(LOG_INFO, "清理临时文件任务执行");
// 实际清理逻辑
}
void backup_database() {
syslog(LOG_INFO, "数据库备份任务执行");
// 实际备份逻辑
}
void check_system_health() {
syslog(LOG_INFO, "系统健康检查执行");
// 实际检查逻辑
}
ScheduledTask tasks[] = {
{0, 300, cleanup_temp_files, "清理临时文件"}, // 每5分钟
{0, 3600, backup_database, "数据库备份"}, // 每小时
{0, 1800, check_system_health, "系统健康检查"}, // 每30分钟
{0, 0, NULL, NULL}
};
void run_scheduled_tasks() {
time_t current_time = time(NULL);
for (int i = 0; tasks[i].task_func != NULL; i++) {
if (current_time - tasks[i].last_run >= tasks[i].interval) {
syslog(LOG_INFO, "执行任务: %s", tasks[i].task_name);
tasks[i].task_func();
tasks[i].last_run = current_time;
}
}
}
int main() {
// 创建Daemon进程
pid_t pid = fork();
if (pid > 0) exit(0);
setsid();
chdir("/");
umask(0);
// 初始化系统日志
openlog("taskscheduler", LOG_PID, LOG_DAEMON);
syslog(LOG_INFO, "任务调度守护进程启动");
// 初始化任务
time_t start_time = time(NULL);
for (int i = 0; tasks[i].task_func != NULL; i++) {
tasks[i].last_run = start_time;
}
// 主循环
while (1) {
run_scheduled_tasks();
sleep(10); // 每10秒检查一次任务
}
closelog();
return 0;
}#!/bin/bash
# mydaemon.sh - Daemon进程管理脚本
case "$1" in
start)
echo "启动守护进程..."
/usr/sbin/mydaemon &
echo $! > /var/run/mydaemon.pid
;;
stop)
echo "停止守护进程..."
kill $(cat /var/run/mydaemon.pid)
rm -f /var/run/mydaemon.pid
;;
restart)
$0 stop
sleep 2
$0 start
;;
status)
if [ -f /var/run/mydaemon.pid ]; then
echo "守护进程正在运行 (PID: $(cat /var/run/mydaemon.pid))"
else
echo "守护进程未运行"
fi
;;
*)
echo "用法: $0 {start|stop|restart|status}"
exit 1
;;
esac普通进程启动
│
├── 执行fork() ────┐
│ │
│ 创建子进程副本
│ │
│ 执行setsid() ← 脱离终端
│ │
│ 改变工作目录到 /
│ │
│ 重设文件权限掩码
│ │
│ 关闭所有文件描述符
│ │
│ 重定向标准I/O到/dev/null
│ │
│ 进入服务主循环
│ │
父进程退出 持续运行
│ (直到系统关闭)
│ │
进程结束 日志记录
错误处理
信号响应
资源清理// 调试模式支持
#ifdef DEBUG
// 在前台运行,输出到控制台
#define LOG(msg) printf("[DEBUG] %s\n", msg)
#else
// 后台运行,记录到系统日志
#define LOG(msg) syslog(LOG_INFO, "%s", msg)
#endifDaemon进程是Linux/Unix系统中不可或缺的组成部分,它们默默地提供着各种基础服务。理解并正确使用Daemon进程,是成为一名优秀系统程序员的重要一步!