Linux daemon programming

Linux daemon

1. Introduction to the Daemon

Daemon is one of the three types of Linux processes. It is a background service process and always runs in the background. It usually runs when the system starts and ends when the system shuts down. The daemon is independent of any terminal, periodically performing a certain task or waiting to process a specific event.
Linux manages processes in the form of sessions and process groups, and each process belongs to a process group. Session number A collection of one or more process groups. Usually, when a user opens a terminal, the system creates a session. All processes running through the terminal belong to this session. When the terminal is closed, all related processes will be terminated. However, the daemon can break through this limitation without being affected by terminal shutdown.

2. Writing the daemon

The creation of the daemon is divided into five steps

2.1 Create a child process, the parent process exits

The parent process exits after creating the child process, and the child process becomes an orphan process and is adopted by the first process (init process), and the child enters into the background to run

pid = fork();
if(pid > 0){
    
    
	exit(0);	//父进程退出
}
2.2 The child process creates a new session
  • Process group: is a collection of one or more processes. It is uniquely represented by the process group ID. In addition to the process ID (PID), the process group is also a necessary attribute of a process. Each process group has a group leader process whose process number is equal to the process group ID, and the process group ID will not be affected by the exit of the group leader process
  • Session period: a collection of one or more process groups. A session starts when the terminal is opened and ends when the terminal is closed. The first process in the session becomes the leader of the session. During this period, all processes run by the user belong to this session period, and the relationship between them is shown in the figure below

The relationship between process group and session period
The function used in this step is setsid(), which is used to create a new session and act as the leader of the session. There are three functions: free the process from the control of the original session; free the process from the control of the original process group; free the process from the control of the original controlling terminal;

/*****setsid()函数*****/
函数原型: pid_t setsid(void)
函数返回值:成功返回该进程组ID;失败返回-1

The child process creates a new session, and the child process becomes the new session leader, getting rid of the original terminal

if(setsid() < 0){
    
    
	exit(-1);
}
2.3 Change the current directory

The child process inherits the current working directory of the parent process. Since the daemon is always running in the background, its working directory cannot be uninstalled, so the working directory needs to be changed. Usually let the root directory be the current working directory of the daemon.
Use the chdir() function, such as chdir("/tmp")

2.4 Reset file permission mask

The child process inherits the file permission mask of the parent process, which has a certain impact on the use of files by the child process. Therefore, setting the file permission mask to 0 can enhance the flexibility of the daemon.
Use the umask() function, such as umask(0)

2.5 Close the file descriptor

The child process inherits some of the opened files of the parent process. These opened files may never be accessed by the daemon, but they also occupy system resources and may also cause the file system where they are located cannot be unloaded.
Use the close() function, the following example

int num;
num = getdtablesize();	//获取当前进程文件描述符表大小
for(i = 0;i < num;i++){
    
    
	close(i);
}

Create a daemon instance

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/stat.h>

int main()
{
    
    
	pid_t pid;
	int i, fd;
	char *buf = "This is a daemon\n";

	pid = fork();	//第一步
	if(pid < 0){
    
    
		printf("Error fork\n");
		exit(1);
	}
	else if(pid > 0){
    
    
		exit(0);	//父进程退出
	}

	setsid();	//第二步
	chdir("/tmp");	//第三步
	umask(0);	//第四步
	for(i = 0;i < getdtablesize();i++){
    
    	  //第五步
		close(i);
	}
	/*这时创建完守护进程,以下开始正式进入守护进程工作*/
	while(1){
    
    
		if((fd = open("daemon.log",O_CREAT|O_WRONLY|O_TRUNC,0600)) < 0){
    
    
			printf("OPen file error\n");
			exit(1);
		}
		write(fd,buf,strlen(buf));
		close(fd);
		sleep(2);
	}
	exit(0);
}

Compile and execute, use tail -f /tmp/daemon.log to see that strings will be written in the corresponding file every 2s. Use the ps command to see that the process is running in the background

linux@linux-virtual-machine:~/andy/proc$ tail -f /tmp/daemon.log
This is a daemon
...
linux@linux-virtual-machine:~/andy/proc$ ps -ef|grep daemon
linux     3184  2001  0 13:01 ?        00:00:00 ./daemon
linux     3247  2001  0 13:04 ?        00:00:00 ./daemon
linux     3250  2667  0 13:05 pts/0    00:00:00 grep --color=auto daemon

3. Error handling of the daemon

Since the daemon process is completely separated from the control terminal, it cannot output error information to the control terminal like a normal process. In general, the daemon process is debugged by using the syslog service, and the error information in the program is entered into the system log file (such as "/var/log/messages"), so that the program problem can be seen intuitively.
syslog is a system log management service in Linux, maintained by the daemon process syslogd. The daemon reads a configuration file "/etc/syslog.conf" when it starts, and the file feels where different kinds of messages will be sent. For example, emergency messages can be sent to the system administrator and displayed on the console, while warning messages can be recorded in a file.
The mechanism provides three syslog related functions, namely:
openlog(): Open a connection to the system log service
syslog(): write messages to the log file, and specify the priority of the message, the message output format, etc.
closelog() : Close the connection to the system log service

/************openlog()函数************/
函数原型:void openlog(char *ident, int option, int facility)
传入值:ident 要向每个消息加入的字符串,通常为程序的名称
	   option 
	   -->LOG_CONS 如果消息无法送到系统日志服务,则直接输出到系统控制终端
	   -->LOG_NDELAY 立即打开系统日志服务的连接,一般直接发送第一条消息时才打开连接
	   -->LOG_PERROR 将消息也同时送到stderr-->LOG_PID 在每条消息中包含进程的PID
	   facility 指定程序发送的消息类型
	   -->LOG_AUTHPRIV 安全/授权信息
	   -->LOG_CRON 时间守护进程(cron及at)
	   -->LOG_DAEMON 其他守护进程
	   -->LOG_KERN 内核信息
	   -->LOG_LOCAL[0~7] 保留
	   -->LOG_LPR 行打印机子系统
	   -->LOG_MAIL 邮件子系统
	   -->LOG_NEWS 新闻子系统
	   -->LOG_SYSLOG syslogd内部所产生的信息
	   -->LOG_USER 一般使用者等级信息
	   -->LOG_UUCP UUCP子系统
/************syslog()函数************/
函数原型:void syslog(int priority, char *format,...)
传入值:priority 
	   -->LOG_EMERG 系统无法使用
	   -->LOG_ALERT 需要立即采取措施
	   -->LOG_CRIT 有重要情况发生
	   -->LOG_ERR 有错误发生
	   -->LOG_WARNING 有警告发生
	   -->LOG_NOTICE 正常情况,但也是重要情况
	   -->LOG_INFO 信息消息
	   -->LOG_DEBUG 调试信息
	   format 以字符串指针的形式表示输出的格式,类似于printf中的格式
/************closelog()函数************/
函数原型:void closelog(void)

Guess you like

Origin blog.csdn.net/Chuangke_Andy/article/details/108303020