python实现监控windows服务并自动启动服务示例


Posted in Python onApril 17, 2014

使用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(
    "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"
    "SUVORK5CYII=")

config.xml

<?xml version="1.0" encoding="utf-8" ?>
<config>
    <!-- 需要监控的服务名称列表 -->
    <services>
        <item>Dhcp</item>
    </services>
    <!-- 间隔时间(单位秒) -->
    <time>10</time>
</config>
Python 相关文章推荐
flask中使用SQLAlchemy进行辅助开发的代码
Feb 10 Python
Python 使用requests模块发送GET和POST请求的实现代码
Sep 21 Python
Python获取某一天是星期几的方法示例
Jan 17 Python
pandas数值计算与排序方法
Apr 12 Python
python抖音表白程序源代码
Apr 07 Python
详解Python3序列赋值、序列解包
May 14 Python
解决tensorflow由于未初始化变量而导致的错误问题
Jan 06 Python
Python实现投影法分割图像示例(一)
Jan 17 Python
Python astype(np.float)函数使用方法解析
Jun 08 Python
python中pop()函数的语法与实例
Dec 01 Python
python反编译教程之2048小游戏实例
Mar 03 Python
Python实现的扫码工具居然这么好用!
Jun 07 Python
解决python写的windows服务不能启动的问题
Apr 15 #Python
Python和php通信乱码问题解决方法
Apr 15 #Python
Python获取脚本所在目录的正确方法
Apr 15 #Python
使用Python获取CPU、内存和硬盘等windowns系统信息的2个例子
Apr 15 #Python
python中使用sys模板和logging模块获取行号和函数名的方法
Apr 15 #Python
python 动态获取当前运行的类名和函数名的方法
Apr 15 #Python
python使用百度翻译进行中翻英示例
Apr 14 #Python
You might like
乱谈我对耳机、音箱的感受
2021/03/02 无线电
解决phpmyadmin中文乱码问题。。。
2007/01/18 PHP
discuz authcode 经典php加密解密函数解析
2020/07/12 PHP
ThinkPHP写数组插入与获取最新插入数据ID实例
2014/11/03 PHP
yii2 页面底部加载css和js的技巧
2016/04/21 PHP
PHP反射API示例分享
2016/10/08 PHP
PHP读取、解析eml文件及生成网页的方法示例
2017/09/04 PHP
使用ucenter实现多站点同步登录的讲解
2019/03/21 PHP
php array_chunk()函数用法与注意事项
2019/07/12 PHP
写js时遇到的一些小问题
2010/12/06 Javascript
分享精心挑选的23款美轮美奂的jQuery 图片特效插件
2012/08/14 Javascript
JS实现跟随鼠标的链接文字提示框效果
2015/08/06 Javascript
Node.js如何使用Diffie-Hellman密钥交换算法详解
2017/09/05 Javascript
微信小程序出现wx.getLocation再次授权问题的解决方法分析
2019/01/16 Javascript
Three.js中矩阵和向量的使用教程
2019/03/19 Javascript
解决vue打包后vendor.js文件过大问题
2019/07/03 Javascript
Vue路由之JWT身份认证的实现方法
2019/08/26 Javascript
Python学习之asyncore模块用法实例教程
2014/09/29 Python
python中黄金分割法实现方法
2015/05/06 Python
Python使用lxml模块和Requests模块抓取HTML页面的教程
2016/05/16 Python
python 地图经纬度转换、纠偏的实例代码
2018/08/06 Python
详解python中的线程与线程池
2019/05/10 Python
Django框架封装外部函数示例
2019/05/28 Python
python爬虫 基于requests模块发起ajax的get请求实现解析
2019/08/20 Python
Python使用Opencv实现边缘检测以及轮廓检测的实现
2020/12/31 Python
关于css中margin的值和垂直外边距重叠问题
2020/10/27 HTML / CSS
加拿大时装零售商:Influence U
2018/12/22 全球购物
乡镇总工会学雷锋活动总结
2014/03/01 职场文书
工作目标责任书
2014/07/23 职场文书
档案工作汇报材料
2014/08/21 职场文书
党员检讨书
2014/10/13 职场文书
父亲去世追悼词
2015/06/23 职场文书
python munch库的使用解析
2021/05/25 Python
使用RedisTemplat实现简单的分布式锁
2021/11/20 Redis
Win11 Build 21996.1 Dev版怎么样? win11系统截图欣赏
2021/11/21 数码科技
JS函数式编程实现XDM一
2022/06/16 Javascript