This is a follow-on to: Getting realtime output using subprocess
I'm trying to use subprocess to capture output from iperf3 in real time (using python 3.6 on windows). The goal is to leave the iperf3 session running continuously and grab the data to update a real time plot.
I created an implementation based on the referenced question (see code at end of post), but the code still waits on the first "readline" call for the iperf3 session to complete.
Output and desired behavior
My code returns the output:
Iperf test
Popen returns after: 0.012966156005859375 seconds
Readline 0 returned after: 3.2275266647338867 seconds, line was: Connecting to host 10.99.99.21, port 5201
Readline 1 returned after: 3.2275266647338867 seconds, line was: [ 4] local 10.99.99.7 port 55563 connected to 10.99.99.21 port 5201
Readline 2 returned after: 3.2275266647338867 seconds, line was: [ ID] Interval Transfer Bandwidth
Readline 3 returned after: 3.2275266647338867 seconds, line was: [ 4] 0.00-0.50 sec 27.4 MBytes 458 Mbits/sec
Readline 4 returned after: 3.2275266647338867 seconds, line was: [ 4] 0.50-1.00 sec 29.0 MBytes 486 Mbits/sec
Exited
The outputs show that the first readline call doesn't return until after 3 seconds, when the iperf session completes. The desired behavior is that the readline calls 0, 1, and 2 return almost immediately, and readline call #3 returns after approx. 0.5 seconds, as soon as iperf3 has completed the first 0.5 second reporting interval.
Code
import subprocess
import time
if __name__ == "__main__":
print('Iperf test')
tref = time.time()
reads_to_capture = 5
times = [0] * reads_to_capture
lines = [''] * reads_to_capture
interval = 0.5
ip = '10.99.99.21' # Iperf server IP address
process = subprocess.Popen(f'iperf3 -c {ip} -f m -i {interval} -t 3', encoding = 'utf-8',
stdout=subprocess.PIPE)
print(f'Popen returns after: {time.time() - tref} seconds')
cnt = 0
while True:
output = process.stdout.readline()
if cnt < reads_to_capture: # To avoid flooding the terminal, only print the first 5
times[cnt] = time.time() - tref
lines[cnt] = output
cnt = cnt + 1
if output == '':
rc = process.poll()
if rc is not None:
break
rc = process.poll()
for ii in range(reads_to_capture):
print(f'Readline {ii} returned after: {times[ii]} seconds, line was: {lines[ii].strip()}')
print('Exited')