ping for indefinite amount of time and get its out

2019-01-20 16:48发布

问题:

The task is: Try to send ping in python using the most basic form like "ping 8.8.8.8". After some time terminate the ping command (In a terminal, one will do Ctrl+C) and get its output. The last several lines of output which shows the ping statistics are of particular interest.

Two methods tried, did not work. My OS version is Mac OS X 10.10.1.

First method uses module pexpect, and ping will stop after about 17 seconds though I did not ask it to stop:

import pexpect
import time
child = pexpect.spawn('ping 8.8.8.8')
(x, y) = child.getwinsize()
print x
print y
time.sleep(21)
child.terminate()
x = child.read()
print x

Second Method uses module subprocess, and the last several lines of ping output are lost:

import time
from subprocess import PIPE, Popen
child = Popen(['ping', '8.8.8.8'], stdin = PIPE, stdout = PIPE, stderr = PIPE)
time.sleep(5)
child.terminate()
x = child.stdout.read()
print x
x = child.stderr.read()
print x

I'd appreciate any help! "ping -c XXX" is not accepted.

回答1:

The second solution you have is great. There's just one issue with obtaining your desired behavior (getting the ping's "conclusion"): You're sending the wrong signal to the process.

When you terminate the process from a shell, you traditionally send a SIGINT signal. See "bash - How does Ctrl-C terminate a child process?". This allows the process to "wrap up" (e.g., cleaning up temprorary files, providing debug information).

import signal

# Open process

child.send_signal(signal.SIGINT)

# Provide some time for the process to complete
time.sleep(1)

# Echo output

Popen.terminate, which you're using now, sends a SIGTERM instead of a SIGINT.



回答2:

ping will block in your code as soon as it fills its stdout OS pipe buffer (~65K on my system). You need to read the output:

#!/usr/bin/env python
import signal
from subprocess import Popen, PIPE
from threading import Timer

child = Popen(['ping', '8.8.8.8'], stdin=PIPE, stdout=PIPE, stderr=PIPE)
Timer(5, child.send_signal, [signal.SIGINT]).start() # Ctrl+C in 5 seconds
out, err = child.communicate() # get output
print(out.decode())
print('*'*60)
print(err.decode())


回答3:

Popen.terminate() sends SIGTERM on Posix OSs. However, by default CTRL+C sends SIGINT. So to get similar behavior like pressing CTRL+C, you can do something like this:

...
import signal
...
time.sleep(5)
child.send_signal(signal.SIGINT)
...