Python Writing daemon Program

Source: Internet
Author: User
Tags session id stdin

Python programming ideas for daemon process

1. Fork child process, parent process exits
Usually, when we execute the service-side program will be connected to the server through the terminal, the successful connection will load the shell environment, terminal and shell are processes, shell process is a child process of the terminal process, through the PS command can be easily viewed. The program that executes at the beginning of the shell environment is a child of the shell process and is naturally affected by the shell process. After the child process is fork in the program, the parent process exits, and for the shell process, the parent process is executed, and the resulting subprocess is taken over by the Init process and thus out of control of the terminal.

2-4 the meaning of the step
The daemon must be isolated from the environment before it is run. These environments include file descriptors that are not closed, control terminals, session and process groups, working directories, and file creation masks.
These environments are typically inherited by daemons from the parent process that executes it, especially the shell.
2, modify the working directory of the child process
The child process inherits the working directory of the parent process when it is created, and if the executed program is in the U disk, it will cause the U disk not to unload. For example, Nginx has its default working directory/etc/nginx/conf.d/default.conf

3. Create a process group
With Setsid, the child process becomes the first session of the new session (session leader), and the child process becomes the lead process for the group, and the child process does not control the terminal.

4, modify the Umask
Because Umask will block permissions, it is set to 0, which avoids permission problems when reading and writing files.

5, fork grandson process, child process exit
After a few steps above, the child process will become the new process group boss, can re-apply to open the terminal, in order to avoid this problem, fork grandson process out.

6. REDIRECT Grandson process standard input stream, standard output stream, standard error stream to/dev/null
Because it is the daemon, itself is out of the terminal, then the standard input stream, standard output stream, standard error stream is meaningless. So all turned to/dev/null, that is, the meaning of discarded.

The way the daemon is started has its special place. It can be started from the startup script/etc/rc.d at system startup, can be started by the inetd Daemon, can have the job planning process Crond started,
It can also be performed by the user terminal (usually the shell).

In short, despite these peculiarities, daemons are basically no different from ordinary processes.
Therefore, the process of writing a daemon is actually transforming a normal process into a daemon based on the nature of the daemon described above. If you understand the process more deeply, it is easy to understand and program the daemon.

Some concepts of Linux system processes

Here is the main answer to the following code questions, why fork? Why to set SID and so on.

This "1" process is the parent process of all processes, because this is CentOS7 it has to start mechanism changes, if in CentOS6 then 1th process is the init process. But no matter how it works is the same.

The daemon that we usually understand is that you execute a program on the command line and it runs in the background, and you exit the terminal and go inside it's still running like Nginx. First we need to know a few concepts

Process ID (PID): is the process number of this process

Parent process ID (PPID): The process's parent process ID number

Process group ID (PGID): Process group ID, each process belongs to a process group, a process group can contain multiple processes that contain a leader process (if the process ID and its corresponding process group ID are the same, the process is the group's leader). For example, a program is multi-process, run the program will start multiple processes, then these processes belong to a process group, because you can send signals to the group, in fact, management.

Session ID (SID): When a new user logs on to Linux, the logon process creates a session for the user. The user's logon shell is the first process of the session. The first process ID of the session is the ID of the entire session. A session is a collection of one or more process groups that contains all the activities of the logged-on user.

Ps-axo Pid,ppid,pgid,sid,tty,comm

Pts/0 is a terminal device bound to the session, where all the PTS/1 is because I opened two connected to the Linux terminal, all through SSH login.

pts/0 process ID is 29641, it has to Ppid and Pgid are the same, indicating that it is the process group 29641 leader, why? Because I am logged in via SSH, the first thing that runs after logging in is bash, which is the program that interacts with me, so you can see that the 29641 parent process ID is 29639 and it is an sshd service.

Why there are so many 1172, the above 1172 is the daemon, the following 29639 is a child process derived from the SSHD service to be responsible for a user's connection, the process ID of 1172 sshd its parent process is 1.

Conversation Group

Usually the commands we execute belong to the front-end task, that is, to the session binding, and if the conversation disappears, the task disappears. I'm going to do a ping here, and it will always execute

We're looking at a different terminal.

Its parent process is 29641, not the bash above us, and its SID is the session ID is also 29641, because it belongs to which session, if which session disappears, this ping operation can also be called a job, that is, disappeared. We shut down the ping terminal and look at the other terminal, and you won't see the ping task. So that's the conversation.

In fact, both the process group and the session belong to the job control. Processes with the same session ID as long as the session disappears, these processes disappear, which is the end.

Let's take a look at the process group

The above command actually runs two processes. We're looking at a different terminal.

Bash's process ID is 30150, so the parent process ID of the child process that it derives from is 30150, just like the following Tailf and grep. This is not a majority, because it is performed on that session, which is the terminal, so they have the same three session ID. As you can see, TAILF and grep have the same process group ID, which is 30374 to indicate that they are in a process group, and that the leader is the TAILF process whose ID is 30374.

Process group ID The same we can signal to the process group, for example, to end all the processes in this group. This is also the content of job management. Do the following:

Kill-sigterm 30374

The task of the other terminal ends automatically.

How do you determine which terminal you are currently in?

Shut down the terminal why do some processes not quit?

Through the SIDs demo we know that the process running on the command line relies on the current session, so the process is not affected by the session so be sure to leave the previous session . Also need to let the process out of the current process can be understood as the current bash is completely cut off the parent-child relationship, because after all, we are running through Bash program, Bash and rely on terminal pts/n this, if bash is gone, the process is gone. See

Or is this the order we put in the background to run,

You can see it's not the same SID as Bash.

But this time if you close the terminal, this task will be gone. You can try it.

Full code
#!/usr/bin/env python# coding:utf-8# python simulation linux daemon import sys, OS, time, atexit, Stringfrom signal import sigterm__m etaclass__ = Typeclass daemon:def __init__ (self, pidfile= "/tmp/daemon.pid", stdin= '/dev/null ', stdout= '/dev/null ', std        Err= '/dev/null '): # need to get debug information, instead stdin= '/dev/stdin ', stdout= '/dev/stdout ', stderr= '/dev/stderr ', run as root. Self.stdin = stdin Self.stdout = stdout Self.stderr = stderr self.pidfile = Pidfile self.appli        Cationname = "Application" Self._homedir = "/" # Debug mode is turned on self._verbose = False # user mask, default is 0 Self._umask = 0 # Gets the daemon mask @property def umask (self): return Self._umask # Sets the daemon mask @umask. Sett Er def umask (self, umask): Self._umask = umask # Gets whether it is currently in debug mode @property def verbosemode (self): RE  Turn Self._verbose # Debug mode switch, default is not debug mode @VerboseMode. Setter def verbosemode (self, verbosemode): Self._verbose = verbosemode # Debug mode and non-adjustableTest mode set def _verbosswitch (self): # debug mode is the output log to the specified file, which specifies if self._verbose:pass when the object is initialized # Self.stdin = '/dev/stdin ' # self.stdout = '/dev/stdout ' # self.stderr = '/dev/stderr ' els E:self.stdin = '/dev/null ' self.stdout = '/dev/null ' self.stderr = '/dev/null ' def SE        Tapplicationname (self, appName): Self.applicationname = appName # Get and set process Live directory @property def Homedir (self): Return Self._homedir @HomeDir. Setter def homedir (self, homedir): Self._homedir = Homedir # The main goal of this method is to break away from the subject and create an environment for the process Def _daemonize (self): # First Step try: # first fork, generate child process, out of parent process, it will return two times, pid if equals 0 description is in child process            Face, if the greater than 0 description is currently in the parent process PID = Os.fork () # If the PID is greater than 0, the description is currently in the parent process, and then Sys.exit (0), the parent process is exited, and the child process is still running.            If pid > 0: # Exits the parent process, at which time Init of the Linux system will take over the child process Sys.exit (0) except OSError, E: Sys.stderr.write (' fork#1 failed:%d (%s) \ n '% (E.errno, e.strerror)) Sys.exit (1) # Combined second step Os.chdir ("/") # Modify Process working directory Os.setsid () # Sets a new session, the child process becomes the first process of a new conversation, and also produces a process group ID with the same session ID Os.umask (self._umask) # Reset file creation permission, that is, the UMA of the working directory SK # Fifth Step try: # The second fork, prohibit the process to open the terminal, equivalent to a child process has derived a subprocess pid = Os.fork () if PID ;                0: # Child process exits, grandson process runs, at this time grandson process is taken over by the Init process, in CentOS 7 is systemed.            Sys.exit (0) except OSError, E:sys.stderr.write (' fork #2 failed:%d (%s) \ n '% (E.errno, e.strerror)) Sys.exit (1) # Sixth Step # put the previous brush on the hard drive Sys.stdout.flush () Sys.stderr.flush () # REDIRECT standard file description Character si = file (Self.stdin, ' r ') so = File (Self.stdout, ' A + ') se = file (self.stderr, ' A + ', 0) # OS The. Dup2 can be atomized to open and copy descriptors, the function is to copy the file descriptor fd to FD2, if there is a need to first close fd2.        Valid in Unix,windows.  # file's Fileno () method returns an integer that is a filename descriptor (descriptor FD Integer) os.dup2 (Si.fileno (), Sys.stdin.fileno ())      Os.dup2 (So.fileno (), Sys.stdout.fileno ()) os.dup2 (Se.fileno (), Sys.stderr.fileno ()) # Register the Exit function, judging by the file PID Whether there is a process atexit.register (self.delpid) pid = str (os.getpid ()) file (Self.pidfile, ' w+ '). Write ('%s\n '% pi d) # Remove PID file after program exit Def delpid (self): Os.remove (Self.pidfile) def start (self, *args, **kwargs): # check P ID file exists to detect if there is a process try:pid = Self._getpid () except ioerror:pid = None # If the PID is stored        On, the process is not closed. If Pid:message = ' pidfile%s already exist.        Process already running!\n ' sys.stderr.write (message% self.pidfile) # program Exit Sys.exit (1) # Construct process Environment Self._daemonize () # Perform specific tasks Self._run (*args, **kwargs) def stop (self): # from PID The file gets pid try:pid = Self._getpid () except ioerror:pid = None # If the program does not start, return directly to the Execute if not pid:message = ' Pidfile%s does not exist. Process not running!\n ' sys.stderr.write (message% self.pidfile) return # Kill Process try:                While 1: # Send signal, kill process Os.kill (PID, SIGTERM) Time.sleep (0.1) Message = ' Process is stopped.\n ' sys.stderr.write (message) except OSError, Err:er                    R = str (ERR) if Err.find (' No such process ') > 0:if os.path.exists (self.pidfile): Os.remove (self.pidfile) else:print str (ERR) Sys.exit (1) # get PID de            F _getpid (self): try: # reads the file that holds the PID pf = files (self.pidfile, ' R ') # converts to integers        PID = Int (Pf.read (). Strip ()) # Close File Pf.close () except ioerror:pid = None Except systemexit:pid = None return PID # Restart function is to kill the previous process, and then run a def restart (self, *args, **kwarg  s): Self.stop ()      Self.start (*args, **kwargs) # Get daemon run status def status (self): Try:pid = Self._getpid () Except ioerror:pid = None if not pid:message = "No Such a process running.\n" sy S.stderr.write (message) Else:message = "The process is running, PID is%s. \ n" sys.stderr.wr ITE (message% STR (PID)) def _run (self, *args, **kwargs): "" Here is what the grandson process needs to do, you can inherit this class, and then rewrite the code here, none of the above can be repaired Change "" "while True:" "Print equals call Sys.stdout.write (), Sys.stdout.flush () is flush output immediately. Normally output to the console will output immediately but redirect to a file will not, because it is equal to write the file, so need to refresh for immediate output.            The following use print or write is the same. "" "# print '%s:hello world\n '% (Time.ctime (),) sys.stdout.write ('%s:hello world\n '% (Time.ctime () ,)) Sys.stdout.flush () Time.sleep (2) if __name__ = = ' __main__ ': daemon = Daemon ('/tmp/watch_proces S.pid ', stdout= '/tmp/watch_stdout.log ') if Len (sys.argv) = = 2:if ' start ' = = Sys.argv[1]: Daemon.setapplicationname (sys.argv[0]) daemon . Start () elif ' stop ' = = Sys.argv[1]: daemon.stop () elif ' restart ' = = Sys.argv[1]: Daem On.restart () elif ' status ' = = Sys.argv[1]: daemon.status () else:print ' Unknown Comman        d ' Sys.exit (2) sys.exit (0) Else:print ' usage:%s start|stop|restart|status '% sys.argv[0] Sys.exit (2)

  

Python Writing daemon Program

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.