Python: subprocess.stdin.write не работает должным образом - PullRequest
3 голосов
/ 13 июля 2011

Я новичок в python, но могу немного кодировать и отлаживать. Следующая проблема была в моей голове в течение прошлых нескольких дней и ищет ответ. Буду признателен за любую оказанную помощь. Задача: я хотел сделать интерактивный telnet (я знаю, что есть библиотека telnet, но мы не используем ее по разным причинам). Для этой цели я использую subprocess.popen

p = subprocess.Popen(telnet_command,
                         stdin = subprocess.PIPE,
                         stdout = outputfileobj,
                         stderr = errorfileobj)

Я провожу опрос (), чтобы узнать, подключился ли сервер к сеансу. Как только я подтвердил, я продолжаю писать в stdin для интерактивного общения.

inputTxt = 'GET / HTTP/1.1\nHost: ' + hostheader + '\n\n'
p.stdin.write(inputTxt)
p.stdin.flush()

Здесь возникла проблема. Я получаю ответ http (или по крайней мере вывод) в течение 5/6 раз, но в 1/6 раза я не получаю вывод, и подпроцесс завершается - что невозможно.

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

16129 write(7, "GET / HTTP/1.1\nHost: www.google."..., 37) = 37
16129 gettimeofday({1310538497, 134474}, NULL) = 0
16129 futex(0x81993a8, FUTEX_WAKE, 1)   = 0
16129 stat64("/etc/localtime", {st_mode=S_IFREG|0644, st_size=56, ...}) = 0
16129 fstat64(4, {st_mode=S_IFREG|0644, st_size=520689, ...}) = 0
16129 _llseek(4, 520689, [520689], SEEK_SET) = 0
16129 stat64("/etc/localtime", {st_mode=S_IFREG|0644, st_size=56, ...}) = 0
16129 write(4, "2011-07-13 06:28:17,134 : pconns"..., 170) = 170
16129 futex(0x81d3b30, FUTEX_WAKE, 1)   = 0
16129 waitpid(16198, 0xffa945e8, WNOHANG) = 0
16129 gettimeofday({1310538497, 135160}, NULL) = 0
16129 fstat64(6, {st_mode=S_IFREG|0644, st_size=81, ...}) = 0
16129 fstat64(6, {st_mode=S_IFREG|0644, st_size=81, ...}) = 0
16129 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xf74b9000
16129 _llseek(6, 0, [0], SEEK_SET)      = 0
16129 fstat64(6, {st_mode=S_IFREG|0644, st_size=81, ...}) = 0
16129 _llseek(6, 0, [0], SEEK_CUR)      = 0
16129 read(6, "Trying 74.125.236.48...\nConnecte"..., 4096) = 81
16129 read(6, "", 4096)                 = 0
16129 close(6)                          = 0
16129 munmap(0xf74b9000, 4096)          = 0
16129 gettimeofday({1310538497, 135778}, NULL) = 0
16129 futex(0x81993a8, FUTEX_WAKE, 1)   = 0
16198 <... select resumed> )            = 1 (in [0])
16198 read(0, "GET / HTTP/1.1\nHost: www.google."..., 8191) = 37
16129 stat64("/etc/localtime",  <unfinished ...>
16198 ioctl(1, TCFLSH, 0)               = -1 ENOTTY (Inappropriate ioctl for device)
16129 <... stat64 resumed> {st_mode=S_IFREG|0644, st_size=56, ...}) = 0
16198 select(4, [0 3], [3], [3], {0, 0}) = 1 (out [3], left {0, 0})
16129 fstat64(4, {st_mode=S_IFREG|0644, st_size=520859, ...}) = 0
16198 send(3, "GET / HTTP/1.1\r\nHos\377\363\377\375\6", 24, 0 <unfinished ...>
16129 _llseek(4, 520859,  <unfinished ...>
16198 <... send resumed> )              = 24
16198 select(4, [0 3], [3], [3], {0, 0} <unfinished ...>
16129 <... _llseek resumed> [520859], SEEK_SET) = 0
16198 <... select resumed> )            = 1 (out [3], left {0, 0})
16198 send(3, ": www.google.com\r\n\r\n", 20, 0 <unfinished ...>
16129 stat64("/etc/localtime",  <unfinished ...>
16198 <... send resumed> )              = 20

Если вы внимательно посмотрите на строку 16198 send (3, "GET / HTTP / 1.1 \ r \ nHos \ 377 \ 363 \ 377 \ 375 \ 6", 24, 0 в трассировке, строка "Hos t " заменяется на некоторую "Hos \ 377 \ 363 \ 377 \ 375 \ 6 ". Я не уверен, почему это происходит время от времени, а также это закрывает соединение с Telnet, которое я установил. Пожалуйста, дайте мне знать, если вам нужно больше данных.

Ответы [ 2 ]

1 голос
/ 17 мая 2017

Хотя общаться лучше, если вам действительно нужно использовать stdin.write , вы можете сделать неблокирующие вызовы используя:

fcntl.fcntl(p.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)

для лучшего понимания прочитайте это:

без блокировки

1 голос
/ 13 июля 2011

Что делать, если вы попытаетесь использовать метод communicate() для отправки данных в подпроцесс вместо использования stdin, поскольку последний не рекомендуется в документации Python :

Предупреждение. Используйте функцию connect () вместо .stdin.write, .stdout.read или .stderr.read, чтобы избежать взаимных блокировок из-за любого другого канала ОС заполнение и блокировка буферов дочернего процесса.

Попробуйте это:

p.communicate(input='GET / HTTP/1.1\nHost: ' + hostheader + '\n\n')
...