zoukankan      html  css  js  c++  java
  • 使用Python实时获取cmd的输出

    最近发现一个问题,一个小伙儿写的console程序不够健壮,监听SOCKET的时候容易崩,造成程序的整体奔溃,无奈他没有找到问题的解决办法,一直解决不了,可是这又是一个监控程序,还是比较要紧的,又必须想办法解决。

    (这是要搞死我的节奏啊....)由于个人不太懂他用的语言,只能在程序外围想办法。

    环境描述:

    1. 目标程序执行时会监听8080端口,TCP,并在每一次client连接后通过console输出client的IP地址。

    2. 监听不是一次性完成的,而是一直监听,程序并不会退出

    3. 为了监控需要,最好能对连接的IP进行排序,整理。

    P.S. 系统基于windows平台。

    想起来做监控程序,简单点比较好,于是想到了Python。

    我的预想逻辑是这样的,通过python检测目标程序是否崩了,如果中标就启动目标程序,并进行监控,每输出一次,python进行一次数据运算整理,然后循环。

    第一步,先搞定输出的捕获问题。

    # this method is used for monitoring
    
    import time
    import subprocess
    import locale
    import codecs
    
    mylist = []
    ps = subprocess.Popen('netstat -a', stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=True)
    while True:
        data = ps.stdout.readline()
        if data == b'':
            if ps.poll() is not None:
                break
        else:
            mylist.append(data.decode(codecs.lookup(locale.getpreferredencoding()).name))
            newlist = []
            for i in mylist:
                if i.find('192.168') > 0:
                    newlist.append(i)
            newlist.sort()
            print('Sum of requests from LAN:', len(newlist))

    我用netstat -a替代那个需要持续输出的程序,执行程序,发现程序和想象的不太一样,确实是实时获得数据了,但是感觉总是有点不太和谐,不管了,继续。

    第二步,解决监控程序的问题

    程序或者还是死的,有一点非常关键,就是监听端口,那只要检测一下端口就行了。三个办法:

    1. 找端口检测的API

    2. 连接一次目标端口,通了就是活的

    3. netstat

    第一种方法需要去找找有没有相关的API,第二种方法容易对目标程序的正常运行造成问题,第三种我想都没想就用了吧。这里需要用到cmd的重定向功能

    # this method is used for monitoring
    
    import time
    import subprocess
    import locale
    import codecs
    
    
    def getstdout(p):
        mylist = []
        while True:
            data = p.stdout.readline()
            if data == b'':
                if p.poll() is not None:
                    break
            else:
                mylist.append(data.decode(codecs.lookup(locale.getpreferredencoding()).name))
        return mylist
    
    while True:
        ps = subprocess.Popen('netstat -an | findstr "8080"', stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=True)
        resultlist = getstdout(ps)
        if len(resultlist) >= 1:
            pass
        else:
            print(time.strftime("%Y-%m-%d %H:%M:%S"))
            subprocess.Popen('taskkill.exe /f /im node.exe', shell=False)
         # 防止动作过快,把新建的程序整死了 time.sleep(
    3) subprocess.Popen('start node D:\app.js', shell=True) time.sleep(10)

    netstat -an获得当前的端口监听情况,“|”将netstat的输出重定向到findstr函数

    netstat -an | findstr "8080" 查找有8080端口的地址行,有就说明活着,否则就是挂了。

    最后一步,整合

    # this method is used for monitoring
    
    import time
    import subprocess
    import locale
    import codecs
    
    
    def getstdout(p):
        mylist = []
        while True:
            data = p.stdout.readline()
            if data == b'':
                if p.poll() is not None:
                    break
            else:
                mylist.append(data.decode(codecs.lookup(locale.getpreferredencoding()).name))
        return mylist
    
    while True:
        ps = subprocess.Popen('netstat -an | findstr "8080"', stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=True)
        resultlist = getstdout(ps)
        if len(resultlist) >= 1:
            pass
        else:
            print(time.strftime("%Y-%m-%d %H:%M:%S"))
            subprocess.Popen('taskkill.exe /f /im node.exe', shell=False)
            time.sleep(3)
            pss = subprocess.Popen('start cmd.exe /k node app.js', stdin=subprocess.PIPE,
                                   stdout=subprocess.PIPE, shell=True)
            alist = getstdout(pss)
            newlist = []
            for i in alist:
                if i.find('192.168') > 0:
                    newlist.append(i)
            newlist.sort()
            print('Sum of requests from LAN:', len(newlist))
        time.sleep(10)

    然后发现有问题,程序完全不会定时检测,只会卡在readline()上。

    各种找问题,发现那个process.stdout.readline()是个同步方法,没结果就不返回。有没有的能异步的方法?

    有人用fnctl,windows不支持,pass

    asyncio?看了半天没太明白...

    折腾了半天,最后关头我还是用c#解决这个问题了....

    参考代码见http://www.jiamaocode.com/Cts/1031.html,打不开的话http://www.cnblogs.com/sode/archive/2012/07/10/2583941.html有转载

    总算解决了这个问题,但是我心中还是不爽,思考了很久如何解决异步readline()的问题。忽然想起来多线程这个利器,干脆开一个线程,不返回就等着,不就问题解决了。

    # this method is used for monitoring
    
    import time
    import subprocess
    import locale
    import codecs
    import threading
    
    
    alist = []
    
    
    def getstdout(p, asy):
        if asy:
            alist.clear()
        mylist = []
        while True:
            data = p.stdout.readline()
            if data == b'':
                if p.poll() is not None:
                    break
            else:
                if asy:
                    alist.append(data.decode(codecs.lookup(locale.getpreferredencoding()).name))
                else:
                    mylist.append(data.decode(codecs.lookup(locale.getpreferredencoding()).name))
        return mylist
    
    while True:
        ps = subprocess.Popen('netstat -an | findstr "8080"', stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=True)
        resultlist = getstdout(ps, False)
        if len(resultlist) >= 1:
            newlist = []
            for i in alist:
                if i.find('192.168') > 0:
                    newlist.append(i)
            newlist.sort()
            print('Sum of requests from LAN:', len(newlist))
        else:
            print(time.strftime("%Y-%m-%d %H:%M:%S"))
            subprocess.Popen('taskkill.exe /f /im node.exe', shell=False)
            time.sleep(3)
            pss = subprocess.Popen('start cmd.exe /k node app.js', stdin=subprocess.PIPE,
                                   stdout=subprocess.PIPE, shell=True)
            th = threading.Thread(target=getstdout, args=[pss, True])
            th.start()
        time.sleep(10)
    View Code

    总结

    有时候简单的解决方法也可以实现同样的功能,对比python的实现与C#的实现,C#更面向事件一点,python应该也有不错的解决方案,继续摸索...

    P.S. 注意cmd输出在UNICODE系统是b''这种类型的字符串,转码对自己系统的默认编码不清楚的建议用codecs.lookup(locale.getpreferredencoding()).name,贸然用utf-8各种坑。

  • 相关阅读:
    第2课 C 到 C++ 的升级
    第1课 学习 C++ 的意义
    归并排序
    插入排序与希尔排序
    选择排序
    冒泡排序
    CodeSignal 刷题 —— almostIncreasingSequence
    CodeSignal 刷题 —— matrixElementSum
    Python3 序列解包
    单星号变量(*)和双星号变量(**)的用法
  • 原文地址:https://www.cnblogs.com/podolski/p/5040107.html
Copyright © 2011-2022 走看看