守护进程(Daemon)是在后台运行的特殊进程,它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。下面我将分析一个典型的Linux守护进程实现代码。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#include <signal.h>
void daemonize()
{
pid_t pid;
/* 1. 创建子进程,父进程退出 */
pid = fork();
if (pid < 0) {
perror("fork failed");
exit(1);
}
if (pid > 0) { // 父进程
exit(0); // 父进程退出
}
/* 2. 在子进程中创建新会话 */
if (setsid() < 0) {
perror("setsid failed");
exit(1);
}
/* 3. 改变当前工作目录到根目录 */
if (chdir("/") < 0) {
perror("chdir failed");
exit(1);
}
/* 4. 重设文件权限掩码 */
umask(0);
/* 5. 关闭文件描述符 */
for (int x = sysconf(_SC_OPEN_MAX); x >= 0; x--) {
close(x);
}
/* 6. 重定向标准输入、输出、错误到/dev/null */
int fd = open("/dev/null", O_RDWR);
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
close(fd);
}
void sig_handler(int signo)
{
if (signo == SIGTERM) {
// 处理终止信号
syslog(LOG_INFO, "received SIGTERM, daemon exiting");
closelog();
exit(0);
}
}
int main()
{
// 守护进程化
daemonize();
// 设置信号处理
signal(SIGTERM, sig_handler);
// 守护进程主循环
while (1) {
// 守护进程的主要工作代码
sleep(10); // 示例:每10秒执行一次
}
return 0;
}
pid = fork();
if (pid > 0) {
exit(0); // 父进程退出
}
if (setsid() < 0) {
perror("setsid failed");
exit(1);
}
if (chdir("/") < 0) {
perror("chdir failed");
exit(1);
}
umask(0);
for (int x = sysconf(_SC_OPEN_MAX); x >= 0; x--) {
close(x);
}
int fd = open("/dev/null", O_RDWR);
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
close(fd);
使用syslog记录日志
c
#include <syslog.h>
openlog("mydaemon", LOG_PID, LOG_DAEMON);
syslog(LOG_INFO, "Daemon started");
实现可靠的信号处理
单实例保证
c
int lockfile = open("/var/run/mydaemon.pid", O_RDWR|O_CREAT, 0640);
if (lockfile < 0) exit(1);
if (lockf(lockfile, F_TLOCK, 0) < 0) exit(0);
资源限制检查
c
struct rlimit rl;
getrlimit(RLIMIT_NOFILE, &rl);
对于现代Linux系统,可以考虑使用以下更简单的方式创建守护进程:
使用daemon()函数
if (daemon(0, 0) < 0) {
perror("daemon failed");
exit(1);
}
使用systemd等init系统
一个健壮的Linux守护进程需要正确处理以下方面: 1. 进程关系(fork和setsid) 2. 文件系统和权限(工作目录和umask) 3. 输入输出重定向 4. 信号处理 5. 日志记录 6. 单实例保证
以上代码和分析提供了一个基本的守护进程实现框架,实际应用中需要根据具体需求进行调整和完善。