# 查看: ps -axj | grep mydaemon
以下为程序过程
import smtplib,re from email.mime.text import MIMEText from email.utils import formataddr import requests,time#引入 正则 时间 和 网络控件 from bs4 import BeautifulSoup import atexit, os, sys, time, signal import os,re,urllib,uuid,json,datetime import pandas as pd #from PIL import Image, ImageDraw, ImageFont #pip install pillow class CDaemon: ''''' a generic daemon class. usage: subclass the CDaemon class and override the run() method stderr 表示错误日志文件绝对路径, 收集启动过程中的错误日志 verbose 表示将启动运行过程中的异常错误信息打印到终端,便于调试,建议非调试模式下关闭, 默认为1, 表示开启 save_path 表示守护进程pid文件的绝对路径 umask=0 u=rwx,g=rwx,o=rwx ;umask=0o022 # u=rwx,g=rx,o=rx 0o1,0o20,0o377 #八进制 (1,16,255) >>>0x01,0x10,0xFF #十六进制 (1,16,255)>>>0b1,0b10000,0b11111111 #二进制 2umask的含义 一 权限掩码umask umask是chmod配套的,总共为4位(gid/uid,属主,组权,其它用户的权限),不过通常用到的是后3个, 例如你用chmod 755 file(此时这文件的权限是属主读(4)+写(2)+执行(1),同组的和其它用户有读写权限) 二 umask的作用 默认情况下的umask值是022(可以用umask命令查看),此时你建立的文件默认权限是644(6-0,6-2,6-2), 建立的目录的默认 权限是755(7-0,7-2,7-2),可以用ls -l验证一下哦 现在应该知道umask的用途了吧,它是为了控制默认权限,不要使默认的文件和目录具有全权而设的 三 修改umask值 知道了umask的作用后,你可以修改umask的值了,例如:umask 024则以后建立的文件和目录的默认权限就为642,753了 总结: 因为老师例子是在往文件里面写内容,所以需要获取文件的可执行权限。 os.umask(0) #修改文件模式,让进程有最大权限,保证进程有读写执行权限,这个不是一个好的方法。 os.setsid() #该方法做一系列的事:首先它使得该进程成为一个新会话的领导者,接下来它将进程转变一个新进程组的领导者 #最后该进程不再控制终端, 运行的时候,建立一个进程,linux会分配个进程号。然后调用os.fork()创建子进程。若pid>0就是自己,自杀。子进程跳过if语句,通过os.setsid()成为linux中的独立于终端的进程(不响应sigint,sighup等)。 ''' def __init__(self, save_path, stdin=os.devnull, stdout=os.devnull, stderr=os.devnull, home_dir='.', umask=0o022, verbose=1): self.stdin = stdin #标准输入 例如键盘输入 self.stdout = stdout #标准输出 命令窗口输出 self.stderr = stderr #标准出错 self.pidfile = save_path #pid文件绝对路径 self.home_dir = home_dir #主目录 根目录 self.verbose = verbose #调试开关 self.umask = umask #文件权限设置掩码 self.daemon_alive = True #进程是否在运行 def daemonize(self): #进程守护化 2次fork try: pid = os.fork() #fork if pid > 0: #正常fork后 为0 否则fork没有成功 sys.exit(0) #无错误 退出,exit(1):有错误退出 except OSError as e: sys.stderr.write('fork #1 failed: %d (%s)\n' % (e.errno, e.strerror)) sys.exit(1) #有错误退出 os.chdir(self.home_dir) #换到根目录 os.setsid() #获得独立进程号 os.umask(self.umask)#设置文件权限掩码 try: pid = os.fork() #再次 fork if pid > 0: sys.exit(0) except OSError as e: sys.stderr.write('fork #2 failed: %d (%s)\n' % (e.errno, e.strerror)) sys.exit(1) sys.stdout.flush() #清除标准输入 sys.stderr.flush() #清除错误信息 si = open(self.stdin, 'r') #打开标准输入 so = open(self.stdout, 'a+') #打开标准输出 if self.stderr: #如果有自定义的出错输出 # se = file(self.stderr, 'a+', 0) se = open(self.stderr, 'a+') #打开出错输出 else: se = so os.dup2(si.fileno(), sys.stdin.fileno()) #os.dup2() 方法用于将一个文件描述符 fd 复制到另一个 fd2。 os.dup2(so.fileno(), sys.stdout.fileno()) os.dup2(se.fileno(), sys.stderr.fileno()) def sig_handler(signum, frame): self.daemon_alive = False signal.signal(signal.SIGTERM, sig_handler) signal.signal(signal.SIGINT, sig_handler) if self.verbose >= 1: print ('daemon process started ...') #进程开始 atexit.register(self.del_pid) #先删除的原有pid文件 pid = str(os.getpid()) open(self.pidfile, 'w+').write('%s\n' % pid) #把pid写到文件里面 def get_pid(self): #取得PID号 try: pf = open(self.pidfile, 'r') pid = int(pf.read().strip()) pf.close() except IOError: pid = None except SystemExit: pid = None return pid def del_pid(self): #删除pid文件 if os.path.exists(self.pidfile): os.remove(self.pidfile) def start(self, *args, **kwargs):#启动开始 if self.verbose >= 1: print( 'ready to starting ......') #check for a pid file to see if the daemon already runs pid = self.get_pid() #取得pid号 if pid: msg = 'pid file %s already exists, is it already running?\n' #pid文件已经存在,已经运行 sys.stderr.write(msg % self.pidfile) #写出错 sys.exit(1) #start the daemon self.daemonize() self.run(*args, **kwargs) def stop(self): #停止 if self.verbose >= 1: print( 'stopping ...') pid = self.get_pid() if not pid: msg = 'pid file [%s] does not exist. Not running?\n' % self.pidfile sys.stderr.write(msg) if os.path.exists(self.pidfile): os.remove(self.pidfile) return #try to kill the daemon process try: i = 0 while 1: os.kill(pid, signal.SIGTERM) time.sleep(0.1) i = i + 1 if i % 10 == 0: os.kill(pid, signal.SIGHUP) except OSError as err: err = 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) if self.verbose >= 1: print ('Stopped!') def restart(self, *args, **kwargs): self.stop() self.start(*args, **kwargs) def is_running(self): pid = self.get_pid() #print(pid) return pid and os.path.exists('/proc/%d' % pid) def run(self, *args, **kwargs): 'NOTE: override the method in subclass' print ('base class run()') 在这加入我们需要运行的程序并定义成一个函数。比如def get() class ClientDaemon(CDaemon): #守护程序 实例 def __init__(self, name, save_path, stdin=os.devnull, stdout=os.devnull, stderr=os.devnull, home_dir='.', umask=0o022, verbose=1): CDaemon.__init__(self, save_path, stdin, stdout, stderr, home_dir, umask, verbose) self.name = name #派生守护进程类的名称 def run(self, output_fn, **kwargs): #运行的程序 在这运行我们加入的函数 get() if __name__ == '__main__': help_msg = 'Usage: python %s <start|stop|restart|status>' % sys.argv[0] if len(sys.argv) != 2: print( help_msg) sys.exit(1) p_name = 'clientd' #守护进程名称 pid_fn = '/tmp/baoxian.pid' #守护进程pid文件的绝对路径 log_fn = '/tmp/baoxian.log' #守护进程日志文件的绝对路径 err_fn = '/tmp/baoxian.err.log' #守护进程启动过程中的错误日志,内部出错能从这里看到 cD = ClientDaemon(p_name, pid_fn, stderr=err_fn, verbose=1) #守护程序 实例开始 if sys.argv[1] == 'start': cD.start(log_fn) elif sys.argv[1] == 'stop': cD.stop() elif sys.argv[1] == 'restart': cD.restart(log_fn) elif sys.argv[1] == 'status': alive = cD.is_running() if alive: print ('process [%s] is running ......' % cD.get_pid()) else: print ('daemon process [%s] stopped'