readline зависает на paramiko.Channel при чтении вывода команды «смотреть» - PullRequest
2 голосов
/ 27 апреля 2020

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

import paramiko

host = "micro"
# timeout = 2  # Succeeds
timeout = 3  # Hangs!
command = 'ls / && watch -n2 \'touch "f$(date).txt"\''

ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_client.connect(host, password='', look_for_keys=False)

transport = ssh_client.get_transport()
channel = transport.open_session()
channel.get_pty()
channel.settimeout(timeout)
channel.set_combine_stderr(True)
stdout = channel.makefile()
channel.exec_command(command)

for line in stdout:  # Hangs here
    print(line.strip())

Есть несколько похожих проблем, некоторые из них довольно старые ( 1 , 2 и, возможно, другие)

Этого не происходит с другими командами, которые тоже не используют watch.

Кто-нибудь знает, что особенного в этой конкретной команде и / или как надежно установить тайм-аут для операции чтения?

(проверено на Python 3.4.2 и paramiko 1.15.1)

Редактировать 1 : я включил channel.set_combine_stderr(True) , как предлагалось в этом ответе на связанный вопрос , но все еще не справился. Тем не менее, watch производит много выходных данных, так что, возможно, проблема именно в этом. Фактически, использование этой команды убрало зависание:

command = 'ls / && watch -n2 \'touch "f$(date).txt"\' > /dev/null'

Так что, вероятно, этот вопрос является почти дубликатом Paramiko s sh die / hang с большим выводом , но заставляет меня Интересно, если действительно нет способа использовать .readline() (в данном случае через __next__) , и нужно прибегать к чтению с фиксированным размером буфера и собирать строки вручную.

1 Ответ

0 голосов
/ 29 апреля 2020

Это, вероятно, зависает, потому что watch не производит переводы строки. Если заменить

for line in stdout:
    print(line.strip())

на занятый l oop на

stdout.readline(some_fixed_size)

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

...