守护进程是 Linux 系统中一种特殊的进程,它是在后台运行的,没有控制终端,不受用户的干扰,负责执行一些系统或者应用相关的任务和功能。守护进程的作用是提高系统的稳定性和效率,以应对一些不可预期的意外或者异常。在嵌入式 Linux 设备中,守护进程可以用来保护系统中的主进程,防止其异常结束后,导致系统完全宕机,破坏用户体验。但是,你真的了解 Linux 下的守护进程吗?你知道如何在 Linux 下编写和使用简单的守护进程吗?本文将为你详细介绍 Linux 下的守护进程的相关知识,让你在 Linux 下更好地使用和理解这个强大的进程类型。
式linux设备中创建一个守护进程,用于保护系统中的主进程,防止某些不可预期的意外导致主进程异常结束后,系统完全宕机没有任何反应,破坏用户体验感。但是,查阅诸多资料之后发现,大部分人都只讲述了如何在x86平台上创建和实现守护进程,而并没有人介绍过如何在嵌入式平台上创建和实现守护进程。于是,经过一番摸索之后,从原理到代码,都进行了一些大致的了解,我自己提出了一些想法。下面就进行一下简单的总结和整理。
下面是网上摘抄的,关于x86的linux系统中对于守护进程的介绍和描述。
守护进程(Daemon)是一种运行在后台的一种特殊的进程,它独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件。
守护进程是个特殊的孤儿进程,这种进程脱离终端,为什么要脱离终端呢?之所以脱离于终端是为了避免进程被任何终端所产生的信息所打断,其在执行过程中的信息也不在任何终端上显示。由于在 Linux 中,每一个系统与用户进行交流的界面称为终端,每一个从此终端开始运行的进程都会依附于这个终端,这个终端就称为这些进程的控制终端,当控制终端被关闭时,相应的进程都会自动关闭。但是守护进程却能突破这种限制,它脱离于终端并且在后台运行,并且它脱离终端的目的是为了避免进程在运行的过程中的信息在任何终端中显示并且进程也不会被任何终端所产生的终端信息所打断。它从被执行的时候开始运转,知道整个系统关闭才退出(当然可以认为的杀死相应的守护进程)。如果想让某个进程不因为用户或中断或其他变化而影响,那么就必须把这个进程变成一个守护进程。
对于x86平台的linux系统,理论上来说,要想实现上述的效果,守护进程具有一套严格的实现步骤。也就是说,守护进程必须在启动伊始,就去除掉一些系统相关的限制,这样才能稳定的在后台运行,而不至于被其他任务所干扰和影响。
下面是在x86平台编写守护进程的基本过程:
–
下面就是摘自某前辈的博客上的全套源码:
#include #include #include #include #include #include #include #include #include #include int init_daemon(void) { int pid; int i; // 1)屏蔽一些控制终端操作的信 号 signal(SIGTTOU,SIG_IGN); signal(SIGTTIN,SIG_IGN); signal(SIGTSTP,SIG_IGN); signal(SIGHU P ,SIG_IGN); // 2)在后台运行 if( pid=fork() ){// 父进程 exit(0);//结束父进程,子进程继 续 }else if(pid 的宏定义 // NOFILE 为文件描述符最大个数,不同系统有不同限 制 for(i=0; i
从上面的流程逻辑和实际代码可以看出,x86平台的守护进程,其实还是比较复杂的,需要进行一堆比较繁琐的初始化过程。然而,对于嵌入式平台而言,流程似乎可以简化一些,不用这么复杂的处理。因为,在本次嵌入式系统中启用守护进程。其目的只是简单的利用这个守护进程来启动另一个被守护的进程,然后定时监控该进程是否仍在正常运行,一旦发现其运行异常,则立即重启该进程就好。
所以,我对上述的流程进行了简化,得到如下的流程:
以下就是在本嵌入式系统项目中所设计的守护进程模块的全套代码。
/****************************************************************************************** ******** ** 函数名称: lockfile ** 功能描述: 对文件加锁/解锁 ** 输入参数: lock: 1表示进行加锁处理, 0表示进行解锁处理 ** 输出参数: 无 ** 返回参 数: 无 ************************************************************************************* *************/ int tryto_lockfile(int fd, int lock) { struct flock fl; fl.l_type = (lock = = 1) ? F_WRLCK : F_UNLCK; fl.l_start = 0; fl.l_whence = SEEK_SET; fl.l_len = 0; return (f cntl(fd, F_SETLK, &fl)); } /*************************************************************** *********************************** ** 函数名称: get_proc_running_state ** 功能描述: 获取进程 运行状态 ** 输入参数: 无 ** 输出参数: 无 ** 返回参数: 返回-1表示路径错误 ** 返回参数: 返回0表示进程 从未运行过,返回1表示进程曾经运行过但是现在停止运行了,返回2表示进程正在运行 中 **************************************************************************************** **********/ static int get_proc_running_state(const char* filename) { int fd; if (filename == NULL) { /* 文件名为 空 */ return -1; } fd = open(filename, O_RDWR, (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)); i f (fd 0) { /* 文件不存在,表示进程从未运行 过 */ return 0; } if (tryto_lockfile(fd, 1) == -1) { /* 文件加锁失败,表示进程在运行 中 */ close(fd); return 2; } else { /* 文件加锁成功,表示进程已经消 失 */ tryto_lockfile(fd, 0); /* 此处要注意记得解锁和关闭文 件 */ close(fd); return 1; } } /*********************************************************** *************************************** ** 函数名称: proc_watch ** 功能描述: 检测进程是否有在运 行,没有运行则重新启动之 ** 输入参数: procname: 进程名 ** 输出参数: 无 ** 返回参数: 返回-1表示进程从 未运行过;返回0表示进程当前运行正常; ** 返回参数: 返回其他非零值表示进程不存在且已被重新启动,返回的值 是新的pid值 *************************************************************************** ***********************/ int proc_watch(const char *procname) { int result, state; char fi lename[100]; result = 0; sprintf(filename, "/var/run/%s.pid", procname); state = get_proc_ running_state(filename); switch (state) { case 0: result = -1; break; case 1: result = sta rt_proc_by_name(procname); break; case 2: result = 0; break; default: break; } return resu lt; } /************************************************************************************ ************** ** 函数名称: start_proc ** 功能描述: 启动进程开始运行 ** 输入参数: 无 ** 输出参 数: 无 ** 返回参数: 进程的ID号,若启动失败则返回 0 ***************************************************************************************** *********/ int start_proc_by_name(const char* procname) { pid_t pid, child_pid; char filen ame[100]; sprintf(filename, "%s%s", PROC_FILE_PATH, procname); child_pid = 0; if (access(f ilename, X_OK | F_OK) != 0) { /* 如果文件存在,并且可执行 */ return 0; } pid = fork(); /* 首 先要fork一个进程出来 */ if (pid 0) { /* 创建进程失 败 */ return 0; } else if (pid == 0) { /* 创建进程成功,此处是子进程的代 码 */ if (execl(filename, procname, (char *)NULL) != -1) { return 1; } else { return 0; } } else { /* 创建进程成功,此处是父进程代 ******************************************************************* ** 函数名 称: thread_client_hdl ** 功能描述: client进程监视线程 ** 输入参数: 无 ** 输出参数: 无 ** 返回参 数: 无 ************************************************************************************* *************/ static void *thread_client_hdl(void *pdata) { int result; pdata = pdata; sl eep(10); /* 第一次要进行延 时 */ for (;;) { printf("time to check thread_client...\n"); result = proc_watch(PROC_NAME _CLIENT); if (result == -1) { printf("thread_client never exist...\n"); } else if (result == 0) { printf("thread_client running ok...\n"); } else { printf("thread_client has gone! but restarted...\n"); } sleep(10); } return NULL; } /************************************* ************************************************************* ** 函数名称: main ** 功能描 述: 入口主函数 ** 输入参数: 无 ** 输出参数: 无 ** 返回参 数: 无 ************************************************************************************* *************/ int main(int argc, char *argv[]) { int client_para; char *p, *process_name; pthread_t thread_client; process_name = argv[0]; /* 获取进程名 称 */ p = process_name + strlen(process_name); while (*p != '/' && p != process_name) { p- -; } if (*p == '/') { process_name = p + 1; } printf("\"%s\" starting...\n", process_name) ; client_para = 0x01; if (pthread_create(&thread_client, NULL, thread_client_hdl, &client_ para) != 0) { printf("create thread_client failed!\n"); return 1; } if (start_proc_by_name (PROC_NAME_CLIENT) == 0) { printf("start thread_client failed!\n"); return 1; } for (;;) { sleep(60); printf("i am still alive...\n"); } return 0; }
通过本文,你应该对 Linux 下的守护进程有了一个基本的了解,知道了它的定义、特点和用途。你也应该明白了如何在 Linux 下编写和使用简单的守护进程,以及使用守护进程时需要注意的一些问题和技巧。我们建议你在使用 Linux 系统时,使用守护进程来提高系统的稳定性和效率。同时,我们也提醒你在使用守护进程时要注意一些潜在的问题和挑战,如信号处理、日志记录、资源管理等。希望本文能够帮助你更好地使用 Linux 系统,让你在 Linux 下掌握守护进程的编写和使用。
以上是Linux 下的守护进程:如何编写和使用简单的守护进程的详细内容。更多信息请关注PHP中文网其他相关文章!