Python實(shí)時(shí)獲取cmd的輸出
最近發(fā)現(xiàn)一個(gè)問(wèn)題,一個(gè)小伙兒寫的console程序不夠健壯,監(jiān)聽(tīng)SOCKET的時(shí)候容易崩,造成程序的整體奔潰,無(wú)奈他沒(méi)有找到問(wèn)題的解決辦法,一直解決不了,可是這又是一個(gè)監(jiān)控程序,還是比較要緊的,又必須想辦法解決。
(這是要搞死我的節(jié)奏啊....)由于個(gè)人不太懂他用的語(yǔ)言,只能在程序外圍想辦法。
環(huán)境描述:
1. 目標(biāo)程序執(zhí)行時(shí)會(huì)監(jiān)聽(tīng)8080端口,TCP,并在每一次client連接后通過(guò)console輸出client的IP地址。
2. 監(jiān)聽(tīng)不是一次性完成的,而是一直監(jiān)聽(tīng),程序并不會(huì)退出
3. 為了監(jiān)控需要,最好能對(duì)連接的IP進(jìn)行排序,整理。
P.S. 系統(tǒng)基于windows平臺(tái)。
想起來(lái)做監(jiān)控程序,簡(jiǎn)單點(diǎn)比較好,于是想到了Python。
我的預(yù)想邏輯是這樣的,通過(guò)python檢測(cè)目標(biāo)程序是否崩了,如果中標(biāo)就啟動(dòng)目標(biāo)程序,并進(jìn)行監(jiān)控,每輸出一次,python進(jìn)行一次數(shù)據(jù)運(yùn)算整理,然后循環(huán)。
第一步,先搞定輸出的捕獲問(wèn)題。
# 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替代那個(gè)需要持續(xù)輸出的程序,執(zhí)行程序,發(fā)現(xiàn)程序和想象的不太一樣,確實(shí)是實(shí)時(shí)獲得數(shù)據(jù)了,但是感覺(jué)總是有點(diǎn)不太和諧,不管了,繼續(xù)。
第二步,解決監(jiān)控程序的問(wèn)題
程序或者還是死的,有一點(diǎn)非常關(guān)鍵,就是監(jiān)聽(tīng)端口,那只要檢測(cè)一下端口就行了。三個(gè)辦法:
1. 找端口檢測(cè)的API
2. 連接一次目標(biāo)端口,通了就是活的
3. netstat
第一種方法需要去找找有沒(méi)有相關(guān)的API,第二種方法容易對(duì)目標(biāo)程序的正常運(yùn)行造成問(wèn)題,第三種我想都沒(méi)想就用了吧。這里需要用到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) # 防止動(dòng)作過(guò)快,把新建的程序整死了 time.sleep(3) subprocess.Popen('start node D:\\app.js', shell=True) time.sleep(10)
netstat -an獲得當(dāng)前的端口監(jiān)聽(tīng)情況,“|”將netstat的輸出重定向到findstr函數(shù)
netstat -an | findstr "8080" 查找有8080端口的地址行,有就說(shuō)明活著,否則就是掛了。
最后一步,整合
# 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)
然后發(fā)現(xiàn)有問(wèn)題,程序完全不會(huì)定時(shí)檢測(cè),只會(huì)卡在readline()上。
各種找問(wèn)題,發(fā)現(xiàn)那個(gè)process.stdout.readline()是個(gè)同步方法,沒(méi)結(jié)果就不返回。有沒(méi)有的能異步的方法?
有人用fnctl,windows不支持,pass
asyncio?看了半天沒(méi)太明白...
折騰了半天,最后關(guān)頭我還是用c#解決這個(gè)問(wèn)題了....
參考代碼見(jiàn)http://www.jiamaocode.com/Cts/1031.html,打不開(kāi)的話http://www.cnblogs.com/sode/archive/2012/07/10/2583941.html有轉(zhuǎn)載
總算解決了這個(gè)問(wèn)題,但是我心中還是不爽,思考了很久如何解決異步readline()的問(wèn)題。忽然想起來(lái)多線程這個(gè)利器,干脆開(kāi)
一個(gè)線程,不返回就等著,不就問(wèn)題解決了。
# 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 ""', stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=True) resultlist = getstdout(ps, False) if len(resultlist) >= : newlist = [] for i in alist: if i.find('.') > : 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() 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()
總結(jié)
有時(shí)候簡(jiǎn)單的解決方法也可以實(shí)現(xiàn)同樣的功能,對(duì)比python的實(shí)現(xiàn)與C#的實(shí)現(xiàn),C#更面向事件一點(diǎn),python應(yīng)該也有不錯(cuò)的解決方案,繼續(xù)摸索...
以上內(nèi)容是小編給大家分享的Python實(shí)時(shí)獲取cmd的輸出的相關(guān)知識(shí),希望大家喜歡。
相關(guān)文章
Python獲取linux主機(jī)ip的簡(jiǎn)單實(shí)現(xiàn)方法
這篇文章主要介紹了Python獲取linux主機(jī)ip的簡(jiǎn)單實(shí)現(xiàn)方法,涉及Python使用socket模塊調(diào)用shell命令的相關(guān)技巧,需要的朋友可以參考下2016-04-04基于Python實(shí)現(xiàn)在線二維碼生成工具
這篇文章將為大家展示如何通過(guò)純Python編程的方式,開(kāi)發(fā)出一個(gè)網(wǎng)頁(yè)應(yīng)用—基于輸入的網(wǎng)址等文字內(nèi)容實(shí)現(xiàn)二維碼的生成,感興趣的可以學(xué)習(xí)一下2022-05-05python之PyAutoGui教你做個(gè)自動(dòng)腳本計(jì)算器的方法
這篇文章主要介紹了python之PyAutoGui教你做個(gè)自動(dòng)腳本計(jì)算器的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03python kmeans聚類簡(jiǎn)單介紹和實(shí)現(xiàn)代碼
這篇文章主要為大家詳細(xì)介紹了python kmeans聚類簡(jiǎn)單介紹和實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-02-02pandas去重復(fù)行并分類匯總的實(shí)現(xiàn)方法
這篇文章主要介紹了pandas去重復(fù)行并分類匯總的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-01-01Python實(shí)現(xiàn)抓取騰訊視頻所有電影的示例代碼
這篇文章主要為大家介紹了如何使用python實(shí)現(xiàn)抓取騰訊視頻所有電影,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-04-04