Consider the following scenario: you write a python service program and start it at the command line, and your command line session is controlled by the terminal, and the python service becomes a child process of the terminal program. So if you close the terminal, the command-line program will close with it.
To make your python service terminal-independent and resident on your system, you need to make it a daemon.
A daemon is a program that executes in the background of the system, independently of the control terminal and performs periodic tasks or triggers events, usually named with a "d" letter ending, such as the common httpd, syslogd, systemd and dockerd.
code implementation
python can be very concise implementation of the daemon, the following code is given first and the corresponding comments:
# coding=utf8 import os import sys import atexit def daemonize(pid_file=None): """ Creating a daemon :param pid_file: file where process ids are stored :return. """ # Fork a child process from the parent process pid = () # The pid of the child process must be 0, the parent process is greater than 0 if pid: # Exit the parent process, the () method performs more buffer flushing than the os._exit() method (0) # The child process inherits the working directory of the parent process by default, it is better to change it to the root directory, otherwise it will affect the uninstallation of the file system. ('/') # The child process inherits the umask (file permission mask) of the parent process by default, reset to 0 (full control) to avoid affecting the program to read and write files. (0) # Make child processes the new session leader and process leader () # Note that this is the 2nd fork, which is the child of the child process, which we call the grandchild process _pid = () if _pid: # Exit sub-processes (0) # At this point, the grandchild process is already a daemon, and the next redirection is to the standard input, output, and error descriptors (redirection rather than shutdown, which prevents the program from making an error when it prints). # Refresh the buffer zone first, you can't be too careful # () () # dup2 function atomically closes and duplicates file descriptors, redirects to /dev/nul, i.e. discards all inputs and outputs with open('/dev/null') as read_null, open('/dev/null', 'w') as write_null: os.dup2(read_null.fileno(), ()) os.dup2(write_null.fileno(), ()) os.dup2(write_null.fileno(), ()) # Write to the pid file if pid_file: with open(pid_file, 'w+') as f: (str(())) # Register the exit function to remove the pid file when the process exits abnormally (, pid_file)
Summarize the steps for writing a daemon:
- fork out the child process and exit the parent process
- Subprocesses change working directory (chdir), file permission mask (umask), process group and session group (setsid)
- Child process forks grandchild process, exits child process
- Grandchild process flushes buffers, redirects standard input/output/errors (generally to /dev/null, meaning discard)
- (Optional) pid write to file
Understanding a few points
Why do you have to fork twice?
The first fork is to get out of the clutches of terminal control. The parent process exits because the terminal sends it a signal when it hits the keyboard, or shuts down; the forked child process becomes an orphaned process after the parent commits suicide, and is in turn taken over by the operating system's init process, and is therefore free from terminal control.
So actually, a second fork is not necessary (the code in many open source projects doesn't fork twice). It's just prudent to prevent the process from opening a control terminal again. Because the child process is now the session leader (the first process in the dialog period), and has the ability to open the control terminal, and fork again, the grandchild process will not be able to open the control terminal.
file descriptor
Linux is "all about files". A file descriptor is an index created by the kernel for an open file, usually a non-negative integer. Processes perform IO operations on file descriptors.
By default, 0 represents standard input, 1 represents standard output, and 2 represents standard error.
umask privilege mask
We know that in Linux, any file has read, write and execute permissions. Among them, the read permission is represented by the number 4, the write permission is 2, the execute permission is 1. The command ls -l can check the file permissions, r/w/x means read/write/execute permissions, respectively.
Any file, there are users (User), user group (Group), other groups (Others) three identity permissions. Generally use three numbers to indicate the file permissions, for example, 754:
- 7, is User permissions, that is, file owner permissions
- 5, is the Group permissions, the owner of the user group of the group members have the right to
- 4, is Others permission, that is, other groups of users' permissions la
And umask is designed to control default permissions and prevent new files or folders from being created with full rights.
The system generally defaults to 022 (viewed with the command umask), which means that the default permissions to create files are 644 and folders are 755. you should be able to see the pattern in them, which is that the sum of file permissions and umask results in 666 (laughs), and the sum of folder permissions and umask results in 777.
process group
Each process belongs to a process group (PG,Process Group), the process group can contain multiple processes.
A process group has a process group leader (Leader), and the ID of the process group leader (PID, Process ID) is used as the ID of the whole process group (PGID, Process Groupd ID).
conversation group
When you log on to a terminal, a session is created, and multiple process groups can be included in a single session. The process that creates the session is the session leader.
A process that is already a session leader cannot call the setsid() method to create a session. Therefore, in the above code, the child process can call setsid(), while the parent process cannot, because it is itself the session leader.
Also, sh (Bourne Shell) does not support the session mechanism, which requires the shell to support Job Control.
Daemons and background processes
With the & symbol, commands can be put into the background for execution. It is different from a daemon:
- The daemon has nothing to do with the terminal and is an orphaned process adopted by the init process; the background process, whose parent process is the terminal, can still print in the terminal
- The daemon remains alive when the terminal is closed; background processes stop when the user exits, unless nohup is added.
- Daemon processes change session, process group, working directory, and file descriptors, and background processes directly inherit from the parent process (shell)
In other words: the guardian process is the aspiring young man who quietly struggles and fights, while the backstage process is the rich young man who silently inherits his dad's assets.
Above is Python create daemon example of the details, more information about Python create daemon please pay attention to my other related articles!