Нет выхода из убитого подпроцесса - PullRequest
0 голосов
/ 30 апреля 2019

У меня есть домашнее задание, чтобы запечатлеть рукопожатие 4 клиента между клиентом и точкой доступа с помощью scapy.Я пытаюсь использовать «aircrack-ng capture.pcap» для проверки правильности рукопожатий в файле захвата, который я создал с помощью scapy

. Я запускаю программу с помощью Popen.программа ждет ввода пользователя, поэтому я должен убить его.когда я пытаюсь получить стандартный вывод после его уничтожения, вывод пуст.

я пробовал stdout.read (), я пытался общаться, я пытался читать stderr, и я пробовал обас ракушками и без

check=Popen("aircrack-ng capture.pcap",shell=True,stdin=PIPE,stdout=PIPE,stderr=PIPE)
check.kill()    
print(check.stdout.read())

Ответы [ 2 ]

1 голос
/ 30 апреля 2019

Хотя вы не должны этого делать (попытка полагаться на жестко заданные задержки по своей природе предрасположена к состоянию гонки), проблема заключается в том, что вы доставляете kill(), пока sh все еще запускается.проблема «решается» (не надежно, но достаточно для демонстрации) крошечным sleep достаточно длинным, чтобы позволить оболочке запуститься и запустить echo:

import time
from subprocess import Popen, PIPE

check=Popen("echo hello && sleep 1000", shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
time.sleep(0.01) # BAD PRACTICE: Race-condition-prone, use one of the below instead.
check.kill()    
print(check.stdout.read())

Тем не менее,гораздо более удачным решением было бы закрыть дескриптор стандартного ввода , чтобы чтения немедленно возвращали 0-байтовые результаты.В более новых версиях Python (современный 3.x) вы можете сделать это с DEVNULL:

import time
from subprocess import Popen, PIPE, DEVNULL

check=Popen("echo hello && read input && sleep 1000", 
            shell=True, stdin=DEVNULL, stdout=PIPE, stderr=PIPE)
print(check.stdout.read())

... или, с Python 2.x, аналогичного эффекта можно достичь, передавпустая строка для communicate(), таким образом close() немедленно отправляет канал stdin:

import time
from subprocess import Popen, PIPE

check=Popen("echo hello && read input && sleep 1000", 
            shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
print(check.communicate('')[0])
0 голосов
/ 30 апреля 2019

Никогда, и я имею в виду, никогда убить процесс как часть нормальной работы. Нет никакой гарантии, насколько далеко он продвинулся к тому моменту, когда вы его уничтожили, поэтому вы не можетеожидайте каких-либо конкретных результатов от него в таком случае.

  • Чтобы явно не передавать ничего подпроцессу в качестве ввода , чтобы предотвратить зависание при попытке прочитать stdin:

  • Используйте <process>.communicate() или используйте subprocess.check_output() вместо Popen для надежного считывания вывода

    • Процесс, в общем случае, не гарантирует вывод каких-либо данных в любой конкретный момент из-за буферизации ввода / вывода.Поэтому вам нужно прочитать выходной поток после завершения процесса, чтобы убедиться, что у вас все есть.
    • В то же время вам необходимо продолжать читать поток в то же время, если процесс может произвести достаточно вывода длязаполнить буфер ввода / вывода 1 .В противном случае он будет зависать, ожидая, пока вы прочитаете буферизованные данные.Если оба stdout и stderr равны PIPE с, вам необходимо прочитать оба , параллельно - т.е. в разных потоках.
      • communicate() и check_output (который использует первый под капотом) достигают этого, читая stdout и stderr в двух отдельных потоках.
  • Предпочитайте вспомогательные функции для Popen для общих случаев использования - в вашем случае check_output - поскольку они позаботятся обо всех вышеупомянутых предостережениях для вас.


1 Трубы полностью буферизованы и типичный размер буфера составляет 64 КБ

...