C++ write LINUX daemon implementation code

  • 2020-09-28 09:02:48
  • OfStack

1. What are daemons

A daemon is a special process that runs in the background. It is independent of the control terminal and periodically performs a task or loop waiting to process the occurrence of certain events.

Daemon process 1 normally starts running when the system is started, and will not stop running until the system is shut down unless it is forcibly terminated.

Daemons 1 generally run with root user privileges because they use special ports or resources;

The daemons' parent process 1 is generally init, because its real parent process quits directly after fork comes out of the daemons, so daemons are orphaned processes, which are taken over by init.

2. What are the common daemons

The logging service process syslogd

Database daemon mysqld

3. Steps to create a daemon

(1) fork() creates the child process, and the parent process exit() exits

This is step 1 of creating a daemon. Since the daemon is detached from the control terminal, completing step 1 creates the illusion that the program is already running in the Shell terminal. All the work after that is done in the child process, while the user in the Shell terminal can execute other commands, thus formally detach from the control terminal and work in the background.

(2) Call the setsid() function in the child process to create a new session

After calling the fork() function, the child process copies the session period, process group, control terminal, etc. of the parent process completely. Although the parent process exits, the session period, process group, control terminal, etc., remain unchanged. Therefore, this is not really independent, while the setsid() function can make the process completely independent.

(3) fork() one more sun process and let the child process exit

Why fork again, assuming there is one kind of situation, before the parent fork have other things to do after the process of the child in the process of doing things blocked for some reason, when the child process because some abnormal reason to quit, can form a zombie process, so the child process fork out 1 Sun Jincheng immediately after exit, Sun Jincheng as daemon will be init took over, at this time, no matter what the parent want to do with it.

(4) Call chdir() function in process Sun to make the root directory "/" become the working directory of process Sun

This step is also necessary, and the child process created with fork inherits the current working directory of the parent process. Since the file system in which the current directory is located (e.g., "/mnt/usb") cannot be unmounted while the process is running, this can cause a lot of trouble for future use (e.g., the system has to go into single-user mode for some reason). Therefore, it is common practice to have "/" as the current working directory of the daemon, which can avoid the above problems, but you can also change the current working directory to another path if you need to, such as /tmp. The common function to change the working directory is chdir.

(5) Call umask() function in the sun process and set the file permission mask of the process to 0

The file permissions mask is used to mask out the corresponding bits in the file permissions. For example, there is a file permissions mask of 050, which blocks the readable and executable permissions of the file group owner. Since the child process created with fork inherited the file permissions mask of the parent process, it caused a lot of trouble for the child process to use the file. Therefore, setting the file permissions mask to 0 greatly enhances the flexibility of the daemon. The function that sets the file permission mask is umask. Here, the usual usage is umask(0).

(6) Close any unwanted file descriptors in the sun process

Like file permissions code 1, a new child created with the fork function inherits 1 opened file from its parent. These open files may never be read or written by the daemon, but they consume system resources and may cause the file system in which they are located to be impossible to unload.

After step 2 above, the daemon has lost contact with the control terminal it belongs to. Therefore, characters entered from the terminal cannot reach the daemon and characters output by the daemon using normal methods (such as printf) cannot be displayed on the terminal. So, the three files with file descriptors 0, 1, and 2 (commonly known as input, output, and error) have lost their value and should be closed.

(7) Daemon exit processing

When a user needs an external stop daemon to run, the kill command is often used to stop the daemon. Therefore, the daemon process needs to be coded to realize the signal signal processing from kill to achieve the normal exit of the process.

4, the code implementation of the daemon


#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
 
static bool flag = true;
void create_daemon();
void handler(int);
 
int main()
{
	time_t t;
	int fd;
	create_daemon();
	struct sigaction act;
	act.sa_handler = handler;
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;
	if(sigaction(SIGQUIT, &act, NULL))
	{
		printf("sigaction error.\n");
		exit(0);
	}
	while(flag)
	{
		fd = open("/home/mick/daemon.log", 
		O_WRONLY | O_CREAT | O_APPEND, 0644);
		if(fd == -1)
		{
			printf("open error\n");
		}
		t = time(0);
		char *buf = asctime(localtime(&t));
		write(fd, buf, strlen(buf));
		close(fd);
		sleep(60);
	}
	return 0;
}
void handler(int sig)
{
	printf("I got a signal %d\nI'm quitting.\n", sig);
	flag = false;
}
void create_daemon()
{
	pid_t pid;
	pid = fork();
	
	if(pid == -1)
	{
		printf("fork error\n");
		exit(1);
	}
	else if(pid)
	{
		exit(0);
	}
 
	if(-1 == setsid())
	{
		printf("setsid error\n");
		exit(1);
	}
 
	pid = fork();
	if(pid == -1)
	{
		printf("fork error\n");
		exit(1);
	}
	else if(pid)
	{
		exit(0);
	}
 
	chdir("/");
	int i;
	for(i = 0; i < 3; ++i)
	{
		close(i);
	}
	umask(0);
	return;
}

5, with the system function daemon to achieve


#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
 
static bool flag = true;
void handler(int);
 
int main()
{
	time_t t;
	int fd;
	if(-1 == daemon(0, 0))
	{
		printf("daemon error\n");
		exit(1);
	}
	struct sigaction act;
	act.sa_handler = handler;
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;
	if(sigaction(SIGQUIT, &act, NULL))
	{
		printf("sigaction error.\n");
		exit(0);
	}
	while(flag)
	{
		fd = open("/home/mick/daemon.log", 
		O_WRONLY | O_CREAT | O_APPEND, 0644);
		if(fd == -1)
		{
			printf("open error\n");
		}
		t = time(0);
		char *buf = asctime(localtime(&t));
		write(fd, buf, strlen(buf));
		close(fd);
		sleep(60);
	}
	return 0;
}
void handler(int sig)
{
	printf("I got a signal %d\nI'm quitting.\n", sig);
	flag = false;
}

The above is the C++ implementation LINUX daemon code instance details, more information about C++ LINUX daemons please follow other related articles on this site!


Related articles: