免费的网站后台管理系统,贵阳做网站的,php做企业网站需要多久,遵化市城乡建设局网站如何编写一个守护进程。我们首先需要理解守护进程是什么。守护进程是在后台运行的进程#xff0c;通常没有控制终端#xff0c;用于执行系统任务#xff0c;比如服务器或者定时任务。 用户可能想创建一个长期运行的服务#xff0c;比如Web服务器或者日志监控程序。
首先通常没有控制终端用于执行系统任务比如服务器或者定时任务。 用户可能想创建一个长期运行的服务比如Web服务器或者日志监控程序。
首先守护进程的创建通常包括几个步骤fork子进程让父进程退出这样终端会认为命令执行完毕子进程继续运行。然后调用setsid创建新的会话脱离终端。接着改变工作目录到根目录避免占用可卸载的文件系统。还要设置文件创建掩码通常是0以拥有更大的灵活性。关闭不需要的文件描述符比如标准输入、输出、错误输出防止它们占用资源。
基于这些步骤创建具体的代码示例。要确保每一步都有对应的代码并且解释清楚每个步骤的作用。例如fork之后父进程退出子进程成为孤儿进程由init进程接管。setsid的作用是让子进程成为新的会话组长脱离原终端的控制。改变工作目录是为了避免守护进程的当前目录被卸载导致问题。设置umask让守护进程创建文件时有默认的权限。关闭文件描述符是为了释放资源可能还需要重定向到/dev/null或者日志文件。另外守护进程的代码编写中可能对信号处理有需求比如处理SIGHUP信号重新加载配置。所以在代码中可能需要添加信号处理函数。此外守护进程可能需要记录日志可以通过syslog或者写入日志文件实现。例如使用openlog和syslog函数。
守护进程遇到的常见问题包括守护进程无法正确脱离终端导致随着终端关闭而终止文件描述符没有正确关闭导致资源泄漏没有正确处理信号导致无法优雅退出或重新加载配置工作目录未改变导致无法卸载文件系统日志记录不当难以调试问题。
在 Linux 系统中守护进程Daemon 是一种在后台长期运行的进程通常独立于控制终端并周期性地执行任务如服务、日志监控等。这篇文章是编写守护进程的标准步骤和代码示例 (1) 进程第1次 fork为进程调用 setsid 作准备。 (2) 进程调用 setsid进程成为新的会话过程的领头进程。 (3) 忽略信号 SIGHUP第2次 fork使进程成为一个新的进程组的领导者。 (4) 关闭所有的文件描述符。 (5) 消除 umask 的影响。 (6) 修改守护进程的当前目录。 (7) 重新定位标准 I/O 描述符。 (8) 保证服务器的互斥运行。 (9) 使用 syslog 来记录守护进程的错误信息。 其中核心步骤为
1 第一次fork为setsid()创建新会话做准备 --- 利用子进程初步和终端进程区分开
2 利用创建的子进程创建出新的会话 --- 进脱离终端的控制
//有的资料就将创建出新会话进程作为守护进程使用是可以的
//为了让守护进程进一步脱离和终端的联系我们需要进行第二次fork
3第二次调用fork() --- 初步得到守护进程//到这一步守护进程已经创建好了后序的操作是进一步修饰守护进程
-------------------------------------------------------------------------------
4 关闭所有打开的文件描述符 --- 守护进程不能有输入也不能有输出
5 消除 uamsk 的影响 --- 对守护进程的进一步处理
6 更改守护进程的工作路径 / --- 确保守护进程能够运行
7 将文件描述符重定向 /dev/null --- 防止关闭的文件描述符再次打开第一次 fork
创建子进程父进程退出。 由于守护进程是脱离控制终端的因此完成第一步后就会在 Shell 终端里造成一程序已经运行完毕的假象。之后的所有后续工作都在子进程中完成而用户在Shell 终端里则可以执行其他的命令从而在形式上做到了与控制终端的脱离。 由于父进程已经先于子进程退出会造成子进程没有父进程从而变成一个孤儿进程。在Linux中每当系统发现一个孤儿进程就会自动由 1号进程收养。原先的子进程就会变成 init进程的子进程。
pidfork(); if (pid 0){fprintf(stderr, “error in first fork.\n”);exit(1);
}if(pid0){ /*父进程退出*/exit(0);
} 在子进程中创建新会话
进程组 进程组是一个或多个进程的集合。进程组由进程组 ID 来唯一标识。除了进程号(PID)之外进 程组ID也一个进程的必备属性之一。 每个进程组都有一个组长进程组长进程的进程号等于进程组 ID。
会话期 会话组是一个或多个进程组的集合。 通常一个会话开始于用户登录终止于用户退出在此期间该用户运行的所有进程都属于这个会话期。
进程组 对话期 与 终端 setsid函数作用
setsid函数用于创建一个新的会话并自任该会话组的组长 新会话的领头进程 让进程摆脱原会话的控制让进程摆脱原进程组的控制让进程摆脱原控制终端的控制
setsid函数能够使进程完全独立出来从而脱离所有其他进程的控制。 子进程继续运行父进程退出的时候将会产生 SIGHUP信号 第一 fork() 的子进程是新的会话过程的领头进程如再打一个终端将成为他的控制终端故需再次 fork()。
忽略信号SIGHUP第二次fork
进程脱离了控制终端与退出的父进程属于同一组进程调用 setgrp()是进程脱离原来的进程组。已经调整好自身位置。
关闭所有文件描述符
服务进程必须关闭它所继承的文件描述符
max_fd sysconf(_SC_OPEN_MAX);
for (i 0; i max_fd;i)close(i);消除umask的影响
每个进程都有一个umask 文件权限掩码是指屏蔽掉文件权限中的对应位。由于使用 fork 新建的子进程继承了父进程的文件权限掩码这就给该子进程使用文件带来了诸多的麻烦。 通常的使用方法为umask(0)增加该守护进程的灵活性umask (0) 清除旧有的文件掩码。 最后的权限 mode ~umask
改变当前目录为根目录
守护进程的当前目录的作用 当进程产生错误的时候将错误信息记录在当前目录的core文件守护进程的特点一般会一直会打开当前目录解决方法找一个不可能被卸载的目录。 通常的做法是让 “/” 作为守护进程的当前工作目录 。
使用fork创建的子进程继承了父进程的当前工作目录。由于在进程运行过程中当前目录所在的 文件系统是不能卸载的这对以后的使用会造成诸多的麻烦(比如进入单用户模式)。
解决方法找一个不可能被卸载的目录 chdir (“/”)。
重新定位标准IO描述符
所有文件描述符都已关闭。 守护进程已不再和终端相关联无标准输入、标准出错文件描述符
printf, perror 等输出语句将出错。打开特殊设备重定位标准的输入、输出描述符
open(“/dev/null”,O_RDWR);dup(1);dup(2);创建守护进程的完整流程
完整代码实现C语言
#include stdio.h
#include stdlib.h
#include unistd.h
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include signal.h
#include syslog.hvoid daemon_init() {pid_t pid;// 1. 创建子进程并终止父进程pid fork();if (pid 0) {perror(fork failed);exit(EXIT_FAILURE);} else if (pid 0) {exit(EXIT_SUCCESS); // 父进程退出}// 2. 创建新会话脱离终端控制if (setsid() 0) {perror(setsid failed);exit(EXIT_FAILURE);}// 3. 忽略 SIGHUP 信号防止会话组长终止导致进程退出signal(SIGCHLD, SIG_IGN);signal(SIGHUP, SIG_IGN);// 4. 再次 fork确保进程不会成为会话组长非必需但更安全pid fork();if (pid 0) {perror(fork failed);exit(EXIT_FAILURE);} else if (pid 0) {exit(EXIT_SUCCESS); // 父进程退出}// 5. 修改工作目录为根目录chdir(/);// 6. 设置文件权限掩码通常设为0umask(0);// 7. 关闭所有打开的文件描述符for (int x sysconf(_SC_OPEN_MAX); x 0; x--) {close(x);}// 8. 重定向标准输入/输出/错误到 /dev/null 或日志文件open(/dev/null, O_RDWR); // stdindup(0); // stdoutdup(0); // stderr// 9. 初始化日志系统可选openlog(mydaemon, LOG_PID, LOG_DAEMON);syslog(LOG_NOTICE, Daemon started successfully);
}int main() {daemon_init();// 守护进程主循环while (1) {syslog(LOG_NOTICE, Daemon is running...);sleep(10);}closelog();return EXIT_SUCCESS;
}编译与运行
编译代码
gcc daemon.c -o mydaemon启动守护进程
./mydaemon验证守护进程 查看进程列表
ps -ef | grep mydaemon检查系统日志Ubuntu 默认在 /var/log/syslog
tail -f /var/log/syslog | grep mydaemon关键步骤详解
两次 fork() 第一次 fork 脱离终端。第二次 fork 确保进程不是会话组长避免重新获取终端控制。 文件描述符处理 关闭所有文件描述符避免资源泄漏。重定向标准输入/输出/错误到 /dev/null 或日志文件。 信号处理 忽略 SIGHUP 和 SIGCHLD防止意外终止。可添加自定义信号处理如 SIGTERM 实现优雅退出。 日志记录 使用 syslog 记录日志便于系统级管理。
另外部分系统如 Linux提供 daemon() 函数简化守护进程创建
使用 daemon() 函数简化
#include unistd.hint main() {if (daemon(0, 0) 0) { // 参数nochdir0切换根目录, noclose0重定向到/dev/nullperror(daemon failed);exit(EXIT_FAILURE);}// 守护进程主逻辑while (1) {sleep(10);}return 0;
}
// 注意事项
// 资源管理确保守护进程释放所有非必要资源如文件描述符。
// 日志监控通过日志文件或 syslog 跟踪守护进程行为。
// 信号处理实现 SIGTERM 或 SIGINT 的优雅退出逻辑。综上。希望该内容能对你有帮助感谢
以上。仅供学习与分享交流请勿用于商业用途转载需提前说明。
我是一个十分热爱技术的程序员希望这篇文章能够对您有帮助也希望认识更多热爱程序开发的小伙伴。 感谢