Home >System Tutorial >LINUX >Daemons in Linux: How to write and use simple daemons
The daemon process is a special process in the Linux system. It runs in the background without a control terminal and is not subject to user interference. It is responsible for performing some system or application-related tasks and functions. The role of the daemon is to improve the stability and efficiency of the system to deal with some unexpected accidents or abnormalities. In embedded Linux devices, daemon processes can be used to protect the main process in the system and prevent it from ending abnormally, causing the system to completely crash and damaging the user experience. But, do you really understand the daemon process under Linux? Do you know how to write and use a simple daemon under Linux? This article will introduce you to the relevant knowledge of daemon processes under Linux in detail, allowing you to better use and understand this powerful process type under Linux.
Create a daemon process in the Linux device to protect the main process in the system and prevent some unexpected accidents from causing the main process to end abnormally, causing the system to completely shut down without any response, destroying the user experience. However, after reviewing a lot of information, I found that most people only talked about how to create and implement daemon processes on the x86 platform, and no one introduced how to create and implement daemon processes on embedded platforms. So, after some exploration and a general understanding of everything from principles to code, I came up with some ideas myself. Below is a brief summary and organization.
The following is an excerpt from the Internet, about the introduction and description of the daemon process in the x86 Linux system.
Daemon is a special process that runs in the background. It is independent of the control terminal and periodically performs certain tasks or waits for processing of certain events.
The daemon process is a special orphan process. This kind of process is separated from the terminal. Why should it be separated from the terminal? The reason why it is separated from the terminal is to prevent the process from being interrupted by information generated by any terminal, and its information during execution will not be displayed on any terminal. Since in Linux, the interface through which each system communicates with users is called a terminal, every process that starts running from this terminal will be attached to this terminal. This terminal is called the control terminal of these processes. When the control terminal is closed, The corresponding processes will be automatically closed. However, the daemon process can break through this limitation. It is separated from the terminal and runs in the background. The purpose of being separated from the terminal is to prevent the information during the running process from being displayed in any terminal and the process will not be accessed by any terminal. Interrupted by the generated terminal message. It starts running when it is executed and does not exit until the entire system is shut down (of course it can be considered as killing the corresponding daemon process). If you want a process not to be affected by user or interruption or other changes, then you must turn this process into a daemon process.
For Linux systems on the x86 platform, theoretically, in order to achieve the above effects, the daemon process has a strict set of implementation steps. In other words, the daemon process must remove some system-related restrictions at the beginning of startup, so that it can run stably in the background without being interfered with and affected by other tasks.
The following is the basic process of writing a daemon on the x86 platform:
–
The following is a complete set of source code taken from a senior’s blog:
#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
It can be seen from the above process logic and actual code that the daemon process of the x86 platform is actually quite complex and requires a lot of tedious initialization processes. However, for embedded platforms, the process seems to be simpler, without such complicated processing. Because, the daemon process is enabled in this embedded system. The purpose is simply to use this daemon process to start another daemonized process, and then regularly monitor whether the process is still running normally. Once it is found that it is running abnormally, just restart the process immediately.
So, I simplified the above process and got the following process:
The following is the complete code of the daemon process module designed in this embedded system project.
/****************************************************************************************** ******** ** 函数名称: 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 下掌握守护进程的编写和使用。
The above is the detailed content of Daemons in Linux: How to write and use simple daemons. For more information, please follow other related articles on the PHP Chinese website!