python实现监控windows服务并自动启动服务示例
使用python 2.7 + pywin32 + wxpython开发
每隔一段时间检测一下服务是否停止,如果停止尝试启动服务。进行服务停止日志记录
appmain.py
#!/usr/bin/env python
#-*- encoding:utf-8 -*-
"""
1. 每隔一分钟检测一次服务状态
2. 如果发现服务状态已经停止,那么尝试启动服务
3. 自动记录日志
4. 任务栏图标显示
"""
import sys;
reload(sys);
sys.setdefaultencoding('utf-8');
import win32service;
import logging;
from logging.handlers import rotatingfilehandler;
import os.path;
import wx;
import appresource;
import webbrowser;
from appxml import *;
c_app_name = "service moniter 1.0";
c_log_dir = os.path.altsep.join([os.path.curdir,'service.log']);
c_config_path = os.path.altsep.join([os.path.curdir,'config.xml']);
c_log_size = 1048576;
c_log_files = 3;
c_app_site = "http://www.du52.com/?app=service_moniter&version=1.0.0";
class servicecontrol(object):
def __init__(self):
self.scm = win32service.openscmanager(none,none,win32service.sc_manager_all_access);
# 检查服务是否停止
def isstop(self,name):
flag = false;
try:
handle = win32service.openservice(self.scm,name,win32service.sc_manager_all_access);
if handle:
ret = win32service.queryservicestatus(handle);
flag = ret[1]!=win32service.service_running;
win32service.closeservicehandle(handle);
except exception,e:
logging.error(e);
return flag;
# 开启服务
def start(self,name):
try:
handle = win32service.openservice(self.scm,name,win32service.sc_manager_all_access);
if handle:
win32service.startservice(handle,none);
win32service.closeservicehandle(handle);
except exception,e:
logging.error(e);
# 退出
def close(self):
try:
if self.scm:
win32service.closeservicehandle(self.scm);
except exception,e:
logging.error(e);
# 初始化日志
def initlog():
logging.getlogger().setlevel(logging.error);
rthandler = rotatingfilehandler(filename=c_log_dir,maxbytes=c_log_size,backupcount=c_log_files);
rthandler.setlevel(logging.error);
rthandler.setformatter(logging.formatter('[%(asctime)s][%(levelname)s] %(message)s'));
logging.getlogger().addhandler(rthandler);
logging.error('监控开始执行');
# 系统托盘图标
class taskicon(wx.taskbaricon):
def __init__(self):
wx.taskbaricon.__init__(self);
self.seticon(appresource.taskicon.geticon(),c_app_name);
self.id_name = wx.newid();
self.id_exit = wx.newid();
self.id_author = wx.newid();
self.bind(wx.evt_menu,self.onexitevent,id=self.id_exit);
self.bind(wx.evt_menu,self.onhelpevent,id=self.id_author);
def onhelpevent(self,event):
webbrowser.open_new(c_app_site);
def onexitevent(self,event):
wx.exit();
def createpopupmenu(self,event=none):
menu = wx.menu();
menu.append(self.id_name,c_app_name);
menu.appendseparator();
menu.append(self.id_author,"技术支持");
menu.append(self.id_exit,"退出");
return menu;
# 隐藏窗口
class frame(wx.frame):
def __init__(self,timelen,services):
wx.frame.__init__(self,parent=none,title=c_app_name);
self.timelen = timelen*1000;
self.services = services;
self.show(false);
self.bind(wx.evt_timer,self.ontimerevent);
self.bind(wx.evt_close,self.onexitevent);
self.timer = wx.timer(self);
self.timer.start(self.timelen);
def ontimerevent(self,event):
sc = servicecontrol();
for name in self.services:
print name;
if sc.isstop(name):
logging.error('系统检测到服务[%s]停止'%(name,));
sc.start(name);
sc.close();
def onexitevent(self,event):
if self.timer:
self.timer.stop();
self.timer = none;
# 进程
class application(wx.app):
def oninit(self):
# 初始化配置
xml = xmlnode();
if not xml.loadfile(c_config_path):
logging.error('配置文件不存在');
return false;
timelen = xml.findnode('time').getint();
if timelen<=0:
logging.error('监控间隔时间必须大于0秒');
return false;
services = xml.findnode('services').getchildrenlist(tag='item');
if len(services)==0:
logging.error('监控服务列表不能为空');
return false;
self.taskbar = taskicon();
self.frame = frame(timelen,services);
return true;
def onexit(self):
logging.error('监控停止执行');
self.frame.close();
self.taskbar.removeicon();
self.taskbar.destroy();
if __name__ == '__main__':
initlog();
app = application();
app.mainloop();
appxml.py
#!/usr/bin/env python
#-*- encoding:utf-8 -*-
"""
xml操作封装
"""
import os.path;
import logging;
import xml.etree.elementtree as elementtree;
class xmlnodevalue(object):
string = 1;
int = 2;
float = 3;
bool = 4;
class xmlnodemap(object):
attr = 1;
text = 2;
node = 3;
class xmlnode(object):
def __init__(self,currentnode=none,rootnode=none):
self.currentnode = currentnode;
self.rootnode = rootnode;
# 加载xml文件
def loadfile(self,path):
if os.path.isabs(path): path = os.path.abspath(path);
flag = false;
try:
self.rootnode = elementtree.parse(path);
if self.rootnode is not none: flag = true;
self.currentnode = self.rootnode;
except exception,e:
logging.error("xml文件加载失败");
logging.error(e.__str__());
return flag;
# 加载xml内容
def loadstring(self,data):
if data is none or len(data.strip())==0: return false;
flag = false;
try:
self.rootnode = elementtree.fromstring(data);
if self.rootnode is not none: flag = true;
self.currentnode = self.rootnode;
except exception,e:
logging.error("xml内容加载失败");
logging.error(e.__str__());
return flag;
# 检查数据是否载入正确
def isload(self):
return self.currentnode is not none and self.rootnode is not none;
# 返回根节点对象
def getroot(self):
return xmlnode(self.rootnode,self.rootnode);
# 查找节点,开始为“/”从根节点开始查找,否则从当前节点查找
def findnode(self,path):
if path is none or len(path.strip())==0: return xmlnode(none,self.rootnode);
path = path.strip();
node = none;
if path[0]=='/':
node = self.rootnode.find(path[1:]);
else:
node = self.currentnode.find(path);
return xmlnode(node,self.rootnode);
# 查找多节点
def findnodes(self,path):
if path is none or len(path.strip())==0: return xmlnode(none,self.rootnode);
if path[0]=='/':
nodes = self.rootnode.findall(path[1:]);
else:
nodes = self.currentnode.findall(path);
return [xmlnode(node,self.rootnode) for node in nodes];
# 获取子节点列表
def getchildrens(self,tag=none):
return [xmlnode(node,self.rootnode) for node in self.currentnode.iter(tag=tag)];
# 格式化数据
def getformatdata(self,node,type):
if type==xmlnodevalue.string:
v = node.getstr();
elif type==xmlnodevalue.int:
v = node.getint();
elif type==xmlnodevalue.float:
v = node.getfloat();
elif type==xmlnodevalue.bool:
v = node.getbool();
else:
v = node.getdata();
return v;
# 获取子节点内容列表
# valueformat 值类型 1 字符串,2 整数,3 小数,4 布尔值
def getchildrenlist(self,tag=none,valueformat=xmlnodevalue.string):
data = [];
for node in self.getchildrens(tag=tag):
data.append(self.getformatdata(node,valueformat));
return data;
# 获取子节点map表
# keytype 1 使用属性值 2 使用子节点
# keyname 属性值名称或子节点名称
# valuetype 1 使用属性值 2 使用子节点
# valuename 属性值名称或子节点名称
def getchildrenmap(self,tag=none,keytype=xmlnodemap.attr,keyname="name",valuetype=xmlnodemap.text,valuename=none,valueformat=xmlnodevalue.string):
data = {};
for node in self.getchildrens(tag=tag):
k,v = none,none;
if keytype==xmlnodemap.attr:
if keyname is none or len(keyname.strip())==0: continue;
k = node.getattrs().getstr(keyname);
elif keytype==xmlnodemap.node:
if keyname is none or len(keyname.strip())==0: continue;
t = node.findnode(keyname);
if not t.isload(): continue;
k = t.getstr();
elif keytype==xmlnodemap.text:
k = node.getstr();
else:
continue;
if k is none or len(k.strip())==0: continue;
if valuetype==xmlnodemap.attr:
if valuename is none or len(valuename.strip())==0: continue;
v = self.getformatdata(node.getattrs(),valueformat);
elif valuetype==xmlnodemap.node:
if valuename is none or len(valuename.strip())==0: continue;
t = node.findnode(valuename);
if t.isload():
v = self.getformatdata(t,valueformat);
elif valuetype==xmlnodemap.text:
v = self.getformatdata(node,valueformat);
else:
v = none;
data[k] = v;
return data;
# 获取节点名称
def gettag(self):
if self.currentnode is none: return "";
return self.currentnode.tag;
# 获取节点内容
def getdata(self,default=none):
if self.currentnode is none: return default;
return self.currentnode.text;
def getstr(self,default="",strip=true):
data = self.getdata();
if data is none: return default;
try:
data = str(data.encode("utf-8"));
if data is none:
data = default;
else:
if strip:
data = data.strip();
except exception,e:
print e;
data = default;
return data;
def getint(self,default=0):
data = self.getdata();
if data is none: return default;
try:
data = int(data);
if data is none: data = default;
except exception:
data = default;
return data;
def getfloat(self,default=0.0):
data = self.getdata();
if data is none: return default;
try:
data = float(data);
if data is none: data = default;
except exception:
data = default;
return data;
def getbool(self,default=false):
data = self.getdata();
if data is none: return default;
data = false;
if self.getstr().lower()=="true" or self.getint()==1: data = true;
return data;
# 获取节点属性
def getattrs(self,default={}):
return xmlattr(self);
class xmlattr(object):
def __init__(self,node):
self.node = node;
self.initattrs();
# 获取node
def getnode(self):
return self.node;
# 设置node
def setnode(self,node):
self.node = node;
self.initattrs();
# 初始化node属性列表
def initattrs(self):
if self.node is none or self.node.currentnode is none:
self.attrs = {};
self.attrs = self.node.currentnode.attrib;
# 获取属性
def getattrs(self):
if self.attrs is none: self.initattrs();
return self.attrs;
# 获取指定属性
def getdata(self,key,default=none):
data = self.attrs.get(key);
if data is none : data = default;
return data;
def getstr(self,key,default="",strip=true):
data = self.getdata(key);
if data is none: return default;
try:
data = str(data.encode("utf-8"));
if data is none:
data = default;
else:
if strip:
data = data.strip();
except exception:
data = default;
return data;
def getint(self,key,default=0):
data = self.getdata(key);
if data is none: return default;
try:
data = int(data);
if data is none: data = default;
except exception:
data = default;
return data;
def getfloat(self,key,default=0.0):
data = self.getdata(key);
if data is none: return default;
try:
data = float(data);
if data is none: data = default;
except exception:
data = default;
return data;
def getbool(self,key,default=false):
data = self.getdata(key);
if data is none: return default;
data = false;
if self.getstr(key).lower()=="true" or self.getint(key)==1: data = true;
return data;
# 测试
if __name__ == "__main__":
node = xmlnode();
print node.loadfile(r"config.xml");
print node.findnode("engine/headers").getchildrenmap("header",xmlnodemap.attr,"name",xmlnodemap.text,none,xmlnodevalue.string);
appresource.py
#----------------------------------------------------------------------
# this file was generated by c:\python27\scripts\img2py
#
from wx.lib.embeddedimage import pyembeddedimage
taskicon = pyembeddedimage(
"ivborw0kggoaaaansuheugaaacaaaaagcayaaabzenr0aaaabhncsvqicagifahkiaaacqdj"
"refuwixfl31s1euvxz/p7+2+997evve2pzbaqmmhcoil9qvbgsjegsmzohrgjtfmwcymy7ko"
"wcky+yejy7kha4zmbweo4xadsp0eqqiifueloptsn9rblklbe+/v3vt7e/yhlwfh1iqso8kv"
"v3++ec73oed8zzmpkfik/o+mzaqqqigndquwxgkxwihejphqsjrxffjqvy0bbszabw1j/f33"
"/+ztucie6+z8cg9ntuv74gd3limldt4ujktstpbcr7esu/rhzcaxjgixmixlissmkeg0rzjf"
"sqi4giptv3flfysxrv+za/fwxff42vmnt452ayrcruuzd8zevh5r8twlhyp2pgv5h7sk7wba"
"r5hatc2clyoaj2skxmegtgxucm2dz65kvc5e0ti44vga3gfpl+6c9+rqpqjirxfb8kj4nwvf"
"xdgjxujspsfl+ooirmkj5qwp8cs4jssywly9zs9efheo03732lpw8lklceeiqidriytkhorc"
"+fwjsbow/4oicbgune2jloc6ett2yoctbdvpunmj4tbpqgszgb9cbdttdxp1umcyfq61zutg"
"kluthcj1bbw7am8o+zewdmm0buztwjrzzlm5crkchaeui2omejkmmglip8hmgela1ihsucqc"
"ssnmfzwxgxg8xlc9ohjf0201jz29ff3nicubw9xz6hvdmp/onimai+m4oi5dc6tjig1djg2o"
"a5af1hweqievbxsnyjf6/yp3iyfyrsloqhhi1cnrmzam9q4ppyalln45ao2ts2984bfrx2hd"
"1xbnre7vthgcrjwgk7cpazjf9hfjf5+j53m4rosis1sz78bxe07f3d5naf1hnsyfw+6a+jrp"
"66/oj8bvpggqmsszgsmxjhwjdxzyaw7h/pllvz14clrba/cfqwulb21przgd00zgazbiamyc"
"w7tdtjax0rtj41k8zypebkgh3bjhvkzjpxg2bzeg3lcc1m4e0q9tvydsdcbcavycgqhgeuwb"
"0bqwtv6mmyp1puemvwa6fycupv27ptr+0b6cm41dhldaenlb8zzg5rfy0v6wxfee61nkciae"
"lugdeurostjzf9voir+oi9evim3xyogpsporngqpkc6qb0xgioh+y5ohdg3uofeeukrz3fz/"
"pfnfz/d0xk5jk8fxlvzxxbqz7e7/bx9e0nxcaetiuy65ewrmlmdedvjrjkwewerbhte3faw0"
"wgncwafcg+qugglcd5gdow7t7emz6r5abuohkx9t+3xhc2mjw17ezwdzfpzl4tg2a85+prg3"
"eixekc+vjitcctqif3kadah8yyh9rzrcqblxoc+xazgslmblieuox3r7ctu3d7dlkz0lvccl"
"9iqqvwqwi9ovtzzt9bwpimvz2lanzec4blxgf3cysgadmq+ifd4cbpruin8cuxkynaqrli1d"
"l6mm0ehqiebmo4phf45qmia8phwsp/0xtwpxlue9i2r4hotvga+01zibexp++lbbpqyicx2y"
"uxwaeawfzmuhhdc+xlewic4zpumlujfh88ahcoe/w0+kpjty+cws2gjm6dfguuzigua1nyeq"
"fy8/v+mnbx7z+agumneu55y/d4sfkh1xef2+h1xvwisqwetxkwtbywizxrbxjbhvc0bhvil1"
"wt+xlb08gcojsmqof+3o4pknxrrfkhqf/cqdaakbmmxhckrcvrt442s/3o09//jhtxw5knp8"
"qdm7s0aioty6shlzb5y3pexzxmhmijpbs2yscajt7zgdmyq1eir80qxhrcvf6idufwntdiud"
"yx+hsuoffja8rsygewoe8pv9binbfd4fhuhjy3dgxt58unpven/k5xelod4anp/qtzx3+gka"
"o4mmguuh2db+5ai+1dthlmnjlfbtqxffknhffsjnasb3brch8ttvpkgjv5op7tu0tcmwdhrd"
"x+fz4fcfup7elljnwtcecoxwzdkz5auqwd4nsre54y+hu6bj8olggkabooug6aiaqrs1itkl"
"jbhlpqlnltfrby0tjxkatxhjmtxy9gd1kewopmlomoau6+i6jqeg8ysoy9ytbw373sifn/wr"
"nm397u0fq4mhczolqnd6qmk6acqogqiggvkdpfhvm4wyo4sysj9acir/echylhl+gp/ssthd"
"b7gs+eenqecsrvfqvrvn1dffaeoeiccrlfubb99ypae6+vwkeuvaja5tnnmd/iqkudxqjcgc"
"haklcvh9d+kqegq2q+gomidrbuc/g4w3d4jbpkrywoenacgv14pdcycnlcpfiqkgcbufdvxq"
"amjpxwndcf28urua07pg66rzcno7g2vetuzftbaicnmigkot1vxhw7kvuqtnf7qtco07qe+c"
"abicea5gbhbfg1+dkovaedsvmu/huz1z7fvl5qrl5iu4lfkrsksumkkch/yconh9qc/rfucg"
"tl0kwznqcm4pdhyencwwmu2qp2yx37v1vqkgon3xpqkosbuqtuzed3ldkzo90xqogqgkqgia"
"1tfs19vvcqycpiu37lqtffznqwcm/z50illtsge874jx/i1mzhj6aisfeapthh6hm+u4bfwb"
"nqbkuerz+mwehjmcaqm0dvqvhkbrz0rr+smenbjuysb5fvm53y6750spzeojvl60qtckqi+c"
"zwa/cl+gn1fopo+j4pmjan4cqr/xoezxucmgbatxoyyl7ptvzi8zgw9av5e/i29vn/h8gmah"
"mulojxljzryh2hvmzcwuvgigub9k3bbennaugmiojbpkt850/owvnc5o9/vdh6kwpazjaijj"
"ag/ue26t8ru9l/1tjfte6qliueitvpihoihjafm0ycf9wgvx8m9fyp/+9kfvv+/scn1qtlou"
"t97yhh95jp1yz2frk/zo375oxznl3c0p/fj2vt0cyy95lx5jdkrxccd6tp0ttmvzrsq4lk1a"
"nxf1hg3znz94mhkwna57de3adx2qqiqu6yoalmxr0bgjqmss1xasbrnes08qhs///f4p5erm"
"zyolffjk9cz/kh+gakuvvvii73i4kawor6/3hcphkplwz31+qwj8l+0/pb1wioqcfx8aaaaa"
"suvork5cyii=")
config.xml
<?xml version="1.0" encoding="utf-8" ?>
<config>
<!-- 需要监控的服务名称列表 -->
<services>
<item>dhcp</item>
</services>
<!-- 间隔时间(单位秒) -->
<time>10</time>
</config>