"怀斯曼不蒸汽啊"
- 任务介绍:
-
- 首先python创建文件1,作用是创建一个守护进程,内容是持续输出时间到输出文件中.
-
- 用shell脚本调用该守护进程
-
- 通过python文件2实现对第一个调度任务的启停重启等.(python的管道操作实现)
1. Linux守护进程介绍
- 普通的进程: 在Linux中,每个系统与用户进行交流的界面成为终端,每一个从此终端开始运行的进程都会依附于这个终端,这个终端被称为这些进程的控制终端,当控制终端被关闭的时候,相应的进程都会自动关闭。
- 守护进程: 如果想让某个进程不因为用户或中断或其他变化而影响,那么就必须把这个进程变成一个守护进程。
用户的登录与注销与守护进程无关系,不受其影响,守护进程自成进程组,自成会话 ,即pid = gid = sid。 - 守护进程也称精灵进程(Daemon),是运行在后台的一种特殊进程。
- 独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程是一种很有用的进程。Linux的大多数服务器就是用守护进程实现的。
1.1 查看进程
ps ajx
可以看到如下界面:
在TPGID一列,数值为-1的,均是脱离终端的守护进程
2. python指令for linux
2.1 运行shell命令
os.system(command)
如下代码可以实现效果如同 ls
import os
os.system('ls')
3. 代码讲解
3.1 创建守护进程文件pre_deal.py
daemonize是创建守护一个进程的过程.其中包括:
- 在后台运行,调用fork ,然后使父进程exit
- 从母体环境脱离,登录会话和进程组,调用setsid()使进程成为会话组长
- 重新fork(防止成为僵尸进程)(此时已经是一个守护进程了)
- 重定向标准文件符(此时的pritf就已经被定向到了输出文件中)
- main函数,就是我们要运行的进程中的任务
#!/usr/bin/env python
#coding: utf-8
import sys, os
'''将当前进程fork为一个守护进程
注意:如果你的守护进程是由inetd启动的,不要这样做!inetd完成了
所有需要做的事情,包括重定向标准文件描述符,需要做的事情只有chdir()和umask()了
'''
def daemonize (stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
#重定向标准文件描述符(默认情况下定向到/dev/null)
try:
pid = os.fork()
#父进程(会话组头领进程)退出,这意味着一个非会话组头领进程永远不能重新获得控制终端。
if pid > 0:
sys.exit(0) #父进程退出
except OSError, e:
sys.stderr.write ("fork #1 failed: (%d) %s\n" % (e.errno, e.strerror) )
sys.exit(1)
#从母体环境脱离
os.chdir("/") #chdir确认进程不保持任何目录于使用状态,否则不能umount一个文件系统。也可以改变到对于守护程序运行重要的文件所在目录
os.umask(0) #调用umask(0)以便拥有对于写的任何东西的完全控制,因为有时不知道继承了什么样的umask。
os.setsid() #setsid调用成功后,进程成为新的会话组长和新的进程组长,并与原来的登录会话和进程组脱离。
#执行第二次fork
try:
pid = os.fork()
if pid > 0:
sys.exit(0) #第二个父进程退出
except OSError, e:
sys.stderr.write ("fork #2 failed: (%d) %s\n" % (e.errno, e.strerror) )
sys.exit(1)
#进程已经是守护进程了,重定向标准文件描述符
for f in sys.stdout, sys.stderr: f.flush()
si = open(stdin, 'r')
so = open(stdout, 'a+')
se = open(stderr, 'a+', 0)
os.dup2(si.fileno(), sys.stdin.fileno()) #dup2函数原子化关闭和复制文件描述符
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
#示例函数:每秒打印一个数字和时间戳
def main():
import time
sys.stdout.write('Daemon started with pid %d\n' % os.getpid())
sys.stdout.write('Daemon stdout output\n')
sys.stderr.write('Daemon stderr output\n')
c = 0
while True:
sys.stdout.write('%d: %s\n' %(c, time.ctime()))
sys.stdout.flush()
c = c+1
time.sleep(3)
if __name__ == "__main__":
daemonize('/dev/null','/tmp/daemon_stdout.log','/tmp/daemon_error.log')
main()
- 可以通过命令
ps -ef | grep pre_deal
查看后台运行的这个进程 - 在/tmp/daemon_error.log会记录错误运行日志
- 在/tmp/daemon_stdout.log会记录标准输出日志。
此时给该文件权限并执行后.查看进程可以看见一个python且,TPGID为-1的守护进程,输出文件也在输出.
3.2 用脚本运行
比较简单:
#/bin/bash
./pre_deal.py
3.3 用一个python程序来管理该任务
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
import time
import subprocess
def start():
os.system("./a")
def stop():
# count = "ps -ef | grep 'pre_deal' | grep 'bin/' | grep -v 'grep' | wc -l"
count = "ps -ef | grep 'pre_deal' | grep -v 'grep' | wc -l" #统计有几行任务
process = subprocess.Popen(count, stdin=None, stdout=subprocess.PIPE,
stderr=None, shell=True)
cnt = process.stdout.read()
if int(cnt):
#此时,cmd是逐个第二列的号码,即PID
cmd = "ps -ef | grep 'pre_deal' | grep -v 'grep' | kill -9 `awk '{print $2}'`"
subprocess.Popen(cmd, stdin=None, stdout=None, stderr=None, shell=True)
# print "All the platform daemons have been stopped."
if __name__ == "__main__":
input_idx = input("请输入1: ")
if input_idx == 1 :
stop()
start()
elif input_idx == 2 :
start()
else:
print("输入错误")
sys.exit(2)
sys.exit(0)
- 基本都是靠python执行shell命令执行,删除操作如下:
- 查询pre_deal相关进程,
wc -l
统计行数,即统计有几个进程
ps -ef | grep 'pre_deal' | grep -v 'grep' | wc -l
awk...print $2
列出第二列的PID,用以杀掉,最后执行kill -9 将这几个与pre_deal有关的进程杀掉,即为关闭
ps -ef | grep 'pre_deal' | grep -v 'grep' | kill -9 `awk '{print $2}'`
- 有一种较为科学规范的方法是,每个守护进程在执行的时候,会生成.pid的文件,其中存放的是该守护进程的PID,而当进程结束时,该文件即销毁.然后可以通过该self.pid的存放内容来杀掉该守护进程.