2013-07-16 3 views
0

Я бег tcpdump внутри Python, и я хотел бы знать, сколько пакетов являются сброшенным ядром.Подпроцесс Python: stderr сохраняет только первую строку. Зачем?

При запуске в командной строке, ТСРйитр выглядит следующим образом:

[email protected]:$ sudo tcpdump -w myPackets.cap -i eth0 ip 
tcpdump: listening on eth2, link-type EN10MB (Ethernet), capture size 65535 bytes 
^C28 packets captured 
28 packets received by filter 
0 packets dropped by kernel 

Это, как я называю tcpdump в моем сценарии Python:

f_out = open("tcpdumpSTDOUT", "w") 
f_err = open("tcpdumpSTDERR", "w") 
tcpdumpProcess = subprocess.Popen(['tcpdump', 
         '-w', 'myPackets.cap', '-i', 'eth0', '-n','ip'], 
         stdout=f_out, 
         stderr=f_err) 
# a few seconds later: 
tcpdumpProcess.kill() 
f_in.close() 
f_out.close() 

Теперь, если я смотрю на tcpdumpSTDERR, я только см. первая из обычных линий вывода:

Tcpdump: прослушивание на eth0, канального типа EN10MB (Ethernet), захват размер 65535 байт

Где все остальное?

EDIT Я попробовал другой подход:

>>> myProcess = subprocess.Popen("tcpdump -w myPackets.cap -i eth2 ip", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 
>>> myProcess.communicate() 

Тогда я убил ТСРйитр из другой оболочки, а выход commnunicate (отображался):

('', 'tcpdump: listening on eth2, link-type EN10MB (Ethernet), capture size 65535 bytes\n') 

... еще первая строка!

EDIT 2 Интересно:

>>> import shlex 
>>> a = subprocess.Popen(shlex.split("tcpdump -w myPackets.cap -i eth2 ip"), stdout=subprocess.PIPE, stderr=subprocess.PIPE) 
>>> a.terminate() 
>>> a.communicate() 
('', 'tcpdump: listening on eth2, link-type EN10MB (Ethernet), capture size 65535 bytes\n221 packets captured\n221 packets received by filter\n0 packets dropped by kernel\n') 
+0

, что в 'f_out'? – inspectorG4dget

+0

абсолютно ничего. Он пуст –

+0

Вы пробовали перенаправление вывода в вызове 'subprocess'? т. е. 'tcpdump ...> tcpdumpSTDOUT' – inspectorG4dget

ответ

1

Проблема заключалась в том, что я назвал kill() на процесс, а не terminate(). С последним все сообщения сохраняются в том, что я указывал как stderr (tcpdump по какой-то причине записывает в stderr, а не в stdout).

Таким образом, в случае, если это может помочь другим, я решил перенаправить поток ошибок в subprocess.PIPE и разобрать строку непосредственно в Python:

>>> tcpdumpProcess = subprocess.Popen(['tcpdump', 
         '-w', 'myPackets.cap', '-i', 'eth0', '-n','ip'], 
         stdout=subprocess.PIPE, 
         stderr=subprocess.PIPE) 
>>> tcpdumpProcess.terminate() 
# stdout in [0], stderr in [1] 
>>> tcpdump_stderr = tcpdumpProcess.communicate()[1] 
>>> print tcpdump_stderr 
tcpdump: listening on eth2, link-type EN10MB (Ethernet), capture size 65535 bytes 
40 packets captured 
40 packets received by filter 
0 packets dropped by kernel 
1

Использование proc.terminate() вместо proc.kill():

import shlex 
import subprocess 
import time 

with open("tcpdumpSTDERR", "wb") as f_err: # close the file automatically 
    proc = subprocess.Popen(shlex.split("tcpdump -w myPackets.cap -i eth2 ip"), 
          stderr=f_err) 
time.sleep(2) # wait a few seconds 
proc.terminate() # send SIGTERM instead of SIGKILL 
proc.wait()  # avoid zombies 
+0

Вы предшествовали мне на 39 секунд :) Одна вещь: зачем SIGTERM генерировать зомби? Я думал, что только SIGKILL может. –

+0

@RickyRobinson: сигнал не имеет значения. Вы должны называть 'proc.wait()', даже если процесс завершается сам по себе без каких-либо внешних сигналов. – jfs

Смежные вопросы