在程序员的生活中,往往会见识到很多高大上的程序;这两天做项目,需要做一个监控C++程序是否运行的,并且程序挂掉后需要自动重启程序;第一个想到的方案是监控进程,但是重新启动程序,却并不是那么容易;好在我们平时一直接触一门强大的“胶水”语言——python,可以完美的完成这两个任务,监控可重启。
思路:
1.启动定时线程
2.检测进程是否存在
3.不存在则启动程序
接下来,我们看看相关需要用到的知识点:
一、Tasklist命令
“Tasklist”命令是一个用来显示运行在本地或远程计算机上的所有进程的命令行工具,带有多个执行参数。
它的使用格式为:
TASKLIST [/S system [/U username [/P [password]]]]
[/M [module] | /SVC | /V] [/FI filter] [/FO format] [/NH]
参数列表:
/S system 指定连接到的远程系统(IP)。
/U [domain]user 指定使用哪个用户执行这个命令。
/P [password] 为指定的用户指定密码。
/M [module] 列出调用指定的 DLL 模块的所有进程。
如果没有指定模块名,显示每个进程加载的所有模块。
/SVC 显示每个进程中的服务。
/V 指定要显示详述信息。
/FI filter 显示一系列符合筛选器指定的进程。
/FO format 指定输出格式,有效值: “TABLE”、“LIST”、“CSV”。
/NH 指定栏标头不应该在输出中显示。
只对 “TABLE” 和 “CSV” 格式有效。
1、 使用“Tasklist”命令查看本机进程
运行“命令提示符”程序,在提示符窗口中输入:“tasklist”命令,这样就显示本机的所有进程。本机的显示结果由五部分组成:图像名(进程名)、PID、会话名、会话#、内存使用。
2、 查看远程系统的进程
在命令提示符下输入:
“tasklist /s 218.22.123.26 /u jtdd /p 12345678”(不包括引号)
其中/s参数后的“218.22.123.26”指要查看的远程系统的IP地址; /u后的“jtdd”指tasklist命令使用的用户帐号,它是远程系统上的一个合法帐号;
/p后的“12345678”指jtdd帐号的密码,。
这样,通过上面的命令,我们就可以查看到远程系统的进程了。
小提示:使用tasklist命令查看远程系统的进程时,需要远程机器的RPC 服务器的支持,否则,该命令就不能正常使用。
3、 查看系统进程提供的服务
tasklist命令不但可以查看系统进程,而且还可以查看每个进程提供的服务。
如查看本机的进程“SVCHOST.EXE”提供的服务,在命令提示符下输入:
“tasklist /svc”命令即可,你会惊奇的发现,有四个“SVCHOST.EXE”进程,原来有二十几项服务使用这个进程,对于远程系统来说,查看系统服务也很简 单,使用” tasklist /s 218.22.123.26 /u jtdd /p 12345678 /svc”命令,就可以查看IP地址为“218.22.123.26”的远程系统进程所提供的服务。
4、 查看调用DLL模块文件的进程列表
例如,我们要查看本地系统中哪些进程调用了“shell32.dll” DLL模块文件。
在命令提示符下输入:
tasklist /m shell32.dll
这时系统将显示调用进程列表。
5、 使用筛选器查找指定的进程 在命令提示符下输入:
“TASKLIST /FI “USERNAME ne NT AUTHORITY\SYSTEM” /FI “STATUS eq running“
这样就列出了系统中正在运行的非“SYSTEM“状态的所有进程。
其中” /FI “为筛选器参数," ne “ 和" eq “为关系运算符”不相等“和”相等“。
[补充]
谈到“Tasklist”命令,我们就不得不提它得孪生兄弟" taskkill "命令,顾名思义,它是用来杀死进程的。
如要杀死本机的 " notepad.exe “进程。
首先,使用Tasklist查找它的PID,系统显示本机” notepad.exe “进程的PID值为” 1132 “,然后运行” taskkill /pid 1132 “即可,或则运行” taskkill /IM notepad.exe “也可;
其中” /pid “参数后面跟要终止进程的PID值,” /IM “参数后面为进程的图像名。
查找java进程就是 tasklist /fi “imagename eq java.exe”
很奇怪这里的的进程是imagename.
用tasklist /?可以查看帮助。
c:> tasklist /fi “IMAGENAME eq pop3svc.exe”
This command returned the following information:
Image Name PID Session Name Session# Mem Usage
POP3Svc.exe 3044 RDP-Tcp#9 0 2,072 K
========================================================
c:> tasklist /fi “PID eq 2500”
Image Name PID Session Name Session# Mem Usage
inetinfo.exe 2500 RDP-Tcp#9 0 5,584 K
========================================================
二、subprocess 库(python)
在Python中,提供了subprocess模块,通过这个模块中的相应API,
就可以开启一个子进程来执行相应的脚本来完成这个操作。
可以通过subprocess中的Popen类来处理这个命令。
即允许你去创建一个新的进程让其执行另外的程序,
并与它进行通信,获取标准的输入、标准输出、标准错误以及返回码等。
subprocess模块定义了一个Popen类,通过它可以创建进程,并与其进行复杂的交互。
__init__(self, args, bufsize=0, executable=None,
stdin=None, stdout=None, stderr=None, preexec_fn=None,
close_fds=False, shell=False, cwd=None, env=None,
universal_newlines=False, startupinfo=None,
creationflags=0)
下面是参数的意思:
参数 | 作用 |
---|---|
args | 一般是一个字符串,是要执行的shell命令内容 |
bufsize | 设置缓冲,负数表示系统默认缓冲,0表示无缓冲,正数表示自定义缓冲行数 |
stdin | 程序的标准输入句柄,NONE表示不进行重定向,继承父进程,PIPE表示创建管道 |
stdout | 程序的标准输出句柄,参数意义同上 |
stderr | 程序的标准错误句柄,参数意义同上,特殊,可以设置成STDOUT,表示与标准输出一致 |
shell | 为True时,表示将通过shell来执行 |
cwd | 用来设置当前子进程的目录 |
env | 设置环境变量,为NONE表示继承自父进程的 |
universal_newlines | 将此参数设置为True,Python统一把这些换行符当作’/n’来处理。 |
进程通信实例
在shell=True这个参数,不写的时候默认是False,shell默认为/bin/sh
。如果 _args_是一个字符串,则该字符串指定要通过shell执行的命令。这意味着字符串的格式必须与在shell提示符下键入时完全相同。这包括,例如,引用或反斜杠转义带有空格的文件名。如果_args_是一个序列,则第一个项指定命令字符串,任何其他项将被视为shell本身的附加参数。也就是说,Popen
相当于:
Popen(['/bin/sh', '-c', args[0], args[1], ...])
communicate()会避免由于输出参数过多造成死锁。返回的是一个tuple,(stdout,stderr)。
注:使用subprocess的时候,第一个填写程序所在位置,第二个填写程序工作目录
subprocess.Popen(r'D:\\Crisis\\game\\f4_chop.exe', cwd=r'D:\\Crisis\\game')
参考:https://www.jianshu.com/p/f1b2653b8561
https://www.jb51.net/article/133941.htm
总结:最重要的就是上面这两部分,这里提供一个简单的案例供参考:
#-*-coding:GBK -*- import threading
import time
import os
import subprocess
import configparser
# get config context config = configparser.ConfigParser()
config.read('config.ini', encoding='GB18030')
path1 = config.get('PATH', 'path1')
path2 = config.get('PATH', 'path2')
def get_process_count(imagename):
p = os.popen('tasklist /FI "IMAGENAME eq %s"' % imagename)
return p.read().count(imagename)
def timer_start():
print("timer_start")
t = threading.Timer(10, watch_func, ["is running..."])
t.start()
def watch_func(msg):
print("I'm watch_func")
if get_process_count('Tt.exe') == 0:
print("get_process_count")
subprocess.Popen(path1,cwd=path2)
timer_start()
if __name__ == "__main__":
timer_start()
while True:
time.sleep(1)
想了解学习更多C++后台服务器方面的知识,请关注:
微信公众号:C++后台服务器开发