Подпроцесс Python.Открытый канал IO неожиданно блокируется - PullRequest
0 голосов
/ 25 апреля 2018

Я пытаюсь использовать subprocess.Popen для управления процессом ssh и взаимодействия с ним по каналам, например так:

p=subprocess.Popen(['ssh','-tt','LOGIN@HOSTNAME'], stdin=subprocess.PIPE,
                    stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                    universal_newlines=True)

while True:
    (out_stdout,out_stderr)=p.communicate(timeout=10)
    if out_stderr:
        print(out_stderr)
    if not out_stdout:
        raise EOFError
    print(out_stdout)

Это прекрасно работает без опции '-tt' для ssh.Однако программа, с которой мне нужно взаимодействовать на удаленной стороне ssh-прерываний, если псевдотермы не выделены, поэтому я вынужден ее использовать.

Похоже, что p.communicate читаетзатем блокируйте на неопределенный срок (или до истечения времени ожидания), даже если ввод доступен.

Я переписал это, используя вызовы низкого уровня для io.read, select.select и т. д., чтобы не проходить через Popen.communicate.Select на самом деле вернет файловый дескриптор как готовый, но последующий io.read к этому файловому дескриптору также заблокируется.Если я отключаю «универсальные переводы строк» ​​и устанавливаю «bufsize = 0» в вызове Popen, то это работает нормально, но затем я вынужден сам выполнить двоичное / юникодное преобразование и обработать завершение строки.

Стоит сказать, чтото, что отключение universal_newlines в версии p.communicate также блокируется на неопределенный срок, так что это не только это.

Любой совет, как я могу получить правильную работу ввода с буферизацией строки без необходимости переопределения всего?

1 Ответ

0 голосов
/ 25 апреля 2018

Существуют библиотечные альтернативы для подпроцесса и двоичного файла SSH, которые лучше подходят для таких задач.

parallel-ssh :

from pssh.pssh2_client import ParalellSSHClient
client = ParallelSSHClient(['HOSTNAME'], user='LOGIN')
output = client.run_command('echo', use_pty=True)

for host, host_output in output.items():
    for line in host_output.stdout:
        print(line)

Заменить echoс помощью команды, которую нужно выполнить, или оставьте как есть, если команда не требуется.Библиотеки требуют, чтобы что-то передавалось как команда, даже если удаленная сторона выполняет что-то автоматически.

См. Также документацию для SSHClient с одним хостом того же проекта.

В соответствии с документацией, разбор строк и кодирование обрабатываются библиотекой, которая также является кроссплатформенной.

Существуют другие, такие как paramiko и ssh2-python, которые являются более низкими уровнями и нуждаются в большем количестве кода для аналогичного выше - см. Их соответствующиедомашние страницы для примеров.

...