python监控windows某个进程的变化

编程学习ing 专栏收录该内容
6 篇文章 0 订阅

本代码是根据网上的资料整理注解而成,亲测程序可以运行。需要安装pywin32的库。
pywin32库下载地址:https://github.com/mhammond/pywin32

!/usr/bin/env python coding=utf-8

# python监控windows某个进程的变化(修正版)
# |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
# | id  |  service  |  pid  |  time  |  status  |  runtime  |
# |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
# 该脚本实际设计用来监控windows某服务和其进程状态的。
# 该脚本设计了两个表,detail_table和result_table,
# 默认5分钟取一次,把结果先写到detail_table,
# 然后把最近两次的结果比较,
# 如果pid发生变化或者服务stop了,
# 就会记录到result_table(所以看结果只看result_table就行)

import win32serviceutil
import win32service
import sqlite3
# SQLite 是一个软件库
# 实现了自给自足的
# 无服务器的
# 零配置的
# 事务性的 SQL 数据库引擎
import os
# os模块提供了非常丰富的方法用来处理文件和目录
import time
# Python  time 模块下有很多函数可以转换常见日期格式。
# 如函数time.time()用于获取当前时间戳。

svcType, svcState, svcControls, err, svcErr, svcCP, svcWH = win32serviceutil.QueryServiceStatus('Dhcp')
if svcState == win32service.SERVICE_STOPPED:
    print('stopped')
elif svcState == win32service.SERVICE_RUNNING:
    print ('running')
elif svcState == win32service.SERVICE_START_PENDING:
    print ('starting')
elif svcState == win32service.SERVICE_STOP_PENDING:
    print ('stopping')

def creatDBandTable(db,dtn,rtn):
    # 创建table
    # 创建detail_table   #dtn
    # 创建result_table   #rtn

    cx = sqlite3.connect(db)
    # 创建数据库/打开数据库:db

    cu = cx.cursor( )
    # cu = cx.cursor()
    # 这样定义了一个游标。游标对象有以下的操作:
    # execute()–执行sql语句
    # executemany–执行多条sql语句
    # close()–关闭游标
    # fetchone()–从结果中取一条记录,并将游标指向下一条记录
    # fetchmany()–从结果中取多条记录
    # scroll()–游标滚动

    cu.execute('create table %s(id integer primary key,service varchar(30),pid integer,time TEXT(30),status integer(10),runtime integer)'%dtn)
    # 创建detail_table
    cu.execute('create table %s(id integer primary key,service varchar(30),pid integer,time TEXT(30),status integer(10),runtime integer)'%rtn)
    # 创建result_table

    cx.commit( )
    # commit( )–事务提交
    # rollback( )–事务回滚
    # close( )–关闭一个数据库连接
    # cursor()–创建一个游标

    cx.close( )

def getInfo( processname ):

    #通过tasklist命令,找到processname的pid
    task=os.popen('tasklist')

    # os.popen( ) 方法用于从一个命令打开一个管道。
    # os.popen(command[, mode[, bufsize]])
    # command -- 使用的命令。
    # mode -- 模式权限可以是 'r'(默认)  'w'
    # bufsize --
    # 指明了文件需要的缓冲大小:
    # 0意味着无缓冲;
    # 1意味着行缓冲;
    # 其它正值表示使用参数大小的缓冲(大概值,以字节为单位)。
    # 负的bufsize意味着使用系统的默认值,
    # 一般来说,对于tty设备,它是行缓冲;
    # 对于其它文件,它是全缓冲。
    # 如果没有改参数,使用系统的默认值。

    # tasklist 是一个command命令,
    # 具体用法,请查看 《tasklist命令参数应用详细图解》
    # tasklist 可以查看目前计算机上运行的所有进程


    if processname in task.read():
            # task.read()是当前进程的信息,具体包含以下信息
            # 映像名称   PID   会话名   会话   内存使用
            # 如果进程中包含 processname 的进程名称
            num = os.popen('tasklist').read().split().index(processname)
                # num 是processname进程的名字,在进程列表的第几个位置

                # Python split() 通过指定分隔符对字符串进行切片,
                # 使用格式:str.split(str="", num=string.count(str)).
                # 如果参数 num 有指定值
                # 则分隔 num+1 个子字符串
                # str = "Line1-abcdef \nLine2-abc \nLine4-abcd";
                # print str.split();  # 以空格为分隔符,包含 \n
                # print str.split(' ', 1);  # 以空格为分隔符,分隔成两个

                # Python index() 方法检测字符串中是否包含子字符串 str 
                # 如果指定 beg(开始)  end(结束) 范围,
                # 则检查是否包含在指定范围内,
                # 该方法与 python find()方法一样,
                # 只不过如果str不在 string中会报一个异常。

                #
                # str1 = "this is string example....wow!!!";
                # str2 = "exam";
                #
                # print str1.index(str2);
                # print str1.index(str2, 10);
                # print str1.index(str2, 40);
                # 15
                # 15
                # Traceback (most recent call last):
                #   File "test.py", line 8, in
                #   print str1.index(str2, 40);
                # ValueError: substring not found
                #
                # shell returned 1


            tasklist = os.popen('tasklist').read().split()
                # tasklist为当前进程所有信息的片段

            index_n = num+1
                # 获取processname进程名字片段的后一个片段,就是processname的pid值

            pid = int(tasklist[index_n])
                # 将processname的pid值(本生是文本型,转换成了整型)

            time1 = time.ctime()
                # Python time ctime() 函数把一个时间戳(按秒计算的浮点数)
                # 转化为time.asctime()的形式。
                # 如果参数未给或者为None的时候,
                # 将会默认time.time()为参数。
                # 它的作用相当于 asctime(localtime(secs))
                # print "time.ctime() : %s" % time.ctime()
                # 以上实例输出结果为:
                # time.ctime() : Tue Feb 17 10:00:18 2013

            status = 1
                #status = 1 means running except Exception e:printe
            print("Sorry ,it ecounter a exception...")
            status_1 = 0
            pid = 0
            time1 = time.ctime()

    else:
            print('Sorry,the process is not in process list,may be not running......')
            status = 0
            pid = 0
            time1 = time.ctime()
    return(pid,time1,status)


def insertDetail(db,detail_table,svc,pid,time1,status,rt1):
    #每次的结果插入到detail_table,返回表中最后一行的id号
    cx=sqlite3.connect(db)
    cu=cx.cursor()
    cu.execute("insert into %s(id,service,pid,time,status,runtime) values(NULL,'%s',%d,'%s',%d,%d)"%(detail_table,svc,pid,time1,status,rt1))
    cx.commit()
    rowid=cu.lastrowid
    cx.close()
    return rowid

def insertResult(db,result_table,svc,pid,time1,status,rt2):
    #当监控服务和进程发生变化,将结果插入到result_table,并返回表中最后一行的id号
    cx=sqlite3.connect(db)
    cu=cx.cursor()
    cu.execute("insert into %s values(NULL,'%s',%d,'%s',%d,%d)"%(result_table,svc,pid,time1,status,rt2))
    cx.commit()
    rowid=cu.lastrowid
    cx.close()
    return rowid

def getpid(db,rowid,table):
    #根据id号,得到表中的pid列的数据
    cx=sqlite3.connect(db)
    cu=cx.cursor()
    cu.execute("select pid,runtime from '%s' where id=%d"%(table,rowid))
    #查找表中的确定id值的pid数据和时间
    value,run_t=cu.fetchone()
    cx.close()
    return(value,run_t)

def getStatus(db,rowid,table):
    #获得表中的status列的值,如果是0,表示stop;1表示running
    cx=sqlite3.connect(db)
    cu=cx.cursor()
    cu.execute("select status,runtime from '%s' where id=%d"%(table,rowid))
    value,runtime1=cu.fetchone()
    cx.close()
    return(value,runtime1)

def updateResultDB(db,table,rowid,rt3):
    # 更新result_table。
    # 因为有一种情况,当监控的服务down了,
    # 其进程也会消失,这是status为0
    # 等到下一次检查时,如果status仍为0
    # 就没有必要再插入一行到表里,我直接更新runtime即可。
    cx=sqlite3.connect(db)
    cu=cx.cursor()
    cu.execute("update '%s' set runtime=%d where id=%d"%(table,rt3,rowid))
    cx.commit()
    cx.close()

def main(dbn,svc,pn):
    # dbn=数据库文件保存的位置
    # svc=监控的服务名称
    # pn=相应的进程名字
    detail_table_n=svc+'_detail'
         #detail_table的真实名字
    result_table_n=svc+'_result'
         #result_table的真实名字
         #初始运行时间指定为0
    if  not os.path.exists(dbn):
        creatDBandTable(dbn,detail_table_n,result_table_n)
        #如果没有数据库文件,就用之前写好的creatDBandTable()创建数据库
        pid,time1,status = getInfo(pn)
            #获取监控进程的pid,当前时间和状态。
            # 如果服务stop了,相应进程也会不存在,
            # 所以我只监控了进程。
        runtime = 0
    if status:
            rowid_old=insertDetail(dbn,detail_table_n,svc,pid,time1,status,0)
            rowid_r=insertResult(dbn,result_table_n,svc,pid,time1,status,0)
            print('Now it will sleep for 5 分钟...')
            time.sleep(5*60)
            pid_old,a = getpid(dbn,rowid_old,detail_table_n)

            while True:
                pid_old,a=getpid(dbn,rowid_old,detail_table_n)
                pid,time1,status=getInfo(pn)
                rowid_d=insertDetail(dbn,detail_table_n,svc,pid,time1,status,300)
                #强制detail_table的rt都为300,不在此记录
                rowid_old=rowid_d
                pid_new,a=getpid(dbn,rowid_d,detail_table_n)

                if  status==0:
                #如果发现进程退出了status_1,
                    status_1, runtime = getStatus(dbn, rowid_r, result_table_n)
                    if  status_1:
                #检查detail表中上一次记录,是不是状态也为0
                # 如果上一次是1
                # 说明该进程是刚刚stop的,
                # 我插入一条记录到result_table;
                # 如果上一次是0,我只update result_table的runtime即可。
                        print('---------------insert-----------------')
                        rowid_r = insertResult(dbn,result_table_n,svc,pid,time1,status,0)
                        time.sleep(5*60)
                        rt1 += 5
                        rt = 0
                        continue
                    else:
                        print('status_1 is 0,just update DB...')
                        runtime+=5
                        updateResultDB(dbn,result_table_n,rowid_r,runtime)
                        time.sleep(5*60)
                        continue
                else:
                    #如果进程未退出status_2,
                    status_2,runtime_r=getStatus(dbn,rowid_r,result_table_n)
                    if status_2:
            #上次未退出
                        if  pid_old!=pid_new:
                #如果pid发生了变化
                            rowid_r=insertResult(dbn,result_table_n,svc,pid_new,time1,status,0)
                            pid_old=pid_new
                            time.sleep(5*60)
                        else:
                #没有变化,则只更新runtime
                            runtime_r+=5
                            updateResultDB(dbn,result_table_n,rowid_r,runtime_r)
                            time.sleep(5*60)
                            continue
                    else:
                #上次退出了
                            rowid_r=insertResult(dbn,result_table_n,svc,pid,time1,status,0)
    else:
        print('Pls. check whether the server is runing...')
        print('Over!')

if __name__=='__main__':
        db_name= r"D:\python\db\6.db"
        #数据库文件保存的位置
        service_name="AliWorkbench"
        #监控的服务名称
        pid_name='AliWorkbench.exe'
        #相应的进程名字
        main(db_name,service_name,pid_name)

  • 1
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值