Get the output of cmd in real time using Python

Recently, I found a problem. The console program written by a guy is not robust enough. When monitoring SOCKET, it is easy to crash, causing the program to crash as a whole. Unfortunately, he has not found a solution to the problem and has been unable to solve it, but this is another monitoring program. It is still more important, and we must find a way to solve it.

(This is going to kill my rhythm....) Since I don't know the language he uses, I can only think of ways outside the program.

 

Environment description:

1. When the target program is executed, it will monitor port 8080, TCP, and output the client's IP address through the console after each client connection.

2. The monitoring is not done at one time, but is always monitored, and the program will not exit

3. In order to monitor the needs, it is best to sort and organize the connected IPs.

The PS system is based on the windows platform.

 

I thought of doing a monitoring program, it is better to be simple, so I thought of Python.

My expected logic is as follows. Use python to detect whether the target program has crashed. If the bid is won, the target program will be started and monitored. After each output, python will perform a data operation and then loop.

The first step is to solve the problem of capturing the output. #

copy code
# 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))
copy code

 

I used netstat -a to replace the program that needs continuous output, execute the program, and found that the program is different from what I imagined. It is indeed real-time to obtain data, but it always feels a little discordant, no matter, continue.

The second step, solve the problem of monitoring program #

The program may still be dead, and a very critical point is to monitor the port, so just check the port. Three ways:

1. Find the API for port detection

2. Connect to the target port once, and it will be alive if it is connected

3. netstat

The first method needs to find out if there is any related API, the second method is easy to cause problems to the normal operation of the target program, and the third method is used without even thinking about it. Here you need to use the redirection function of cmd

copy code
# 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) 
     # Prevent the action from moving too fast and kill the newly created program time.sleep(
3) subprocess.Popen('start node D:\\app.js', shell=True) time.sleep(10)
copy code

netstat -an gets the current port listening status, "|" redirects the output of netstat to the findstr function

netstat -an | findstr "8080" Find the address line with port 8080, if there is, it means it is alive, otherwise it is hung up.

 

The last step, integration #

copy code
# 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)
copy code

Then it is found that there is a problem, the program will not detect it regularly at all, it will only be stuck on readline().

Looking for various problems, I found that process.stdout.readline() is a synchronous method, and it will not return if there is no result. Is there a way to do this asynchronously?

Some people use fnctl, windows do not support, pass

asyncio? I didn't understand it for a long time...

After tossing for a long time, I still use c# to solve this problem at the last minute. …

See http://www.jiamaocode.com/Cts/1031.html for the reference code, if you can't open it, http://www.cnblogs.com/sode/archive/2012/07/10/2583941.html has a reprint

 

I finally solved this problem, but I was still unhappy and thought about how to solve the problem of asynchronous readline() for a long time. Suddenly I think of multi-threading, a powerful tool, simply open a thread and wait if it does not return, otherwise the problem will be solved.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 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()

  

Summary #

Sometimes simple solutions can also achieve the same function. Comparing the implementation of python with the implementation of C#, C# is more event-oriented. Python should also have a good solution, continue to explore...

PS Note that the cmd output is a string of type b'' in the UNICODE system. It is recommended to use codecs.lookup(locale.getpreferredencoding()).name if the transcoding is unclear about the default encoding of your own system, and use utf-8 rashly. kind of pit.

Related: Get the output of cmd in real time using Python