一般 SSH 错误 - 读取 SSH 协议横幅时出错
Posted
技术标签:
【中文标题】一般 SSH 错误 - 读取 SSH 协议横幅时出错【英文标题】:General SSH error - Error reading SSH protocol banner 【发布时间】:2017-10-05 15:06:17 【问题描述】:我正在用 kivy 编写一个 python UI 来管理一些带有结构的远程机器。由于我不能在 Windows 10 上使用 Fabric 的并行实现(参见 here),我希望使用 parallel-ssh 来实际执行并行远程操作。这个问题似乎是由库之间的交互引起的,而不是其中任何一个问题。
我已尝试按照here 的建议手动加载我的私钥:
from fabric.api import execute
import pssh
from pssh.utils import load_private_key
hosts = ['192.168.0.2']
private_key = load_private_key('C:/Users/democracy/.ssh/id_rsa')
pssh_client = pssh.ParallelSSHClient(hosts, user='XXX', password='YYY', pkey=private_key)
output = pssh_client.run_command('whoami', sudo=True)
pssh_client.join(output)
for host in output:
for line in output[host]['stdout']:
print("Host %s - output: %s" % (host, line))
以上代码导致以下回溯:
Exception: Error reading SSH protocol banner('This operation would block forever', <Hub at 0x242566ab9c8 select pending=0 ref=0>)
Traceback (most recent call last):
File "C:\environments\democracy\lib\site-packages\paramiko\transport.py", line 1884, in _check_banner
buf = self.packetizer.readline(timeout)
File "C:\environments\democracy\lib\site-packages\paramiko\packet.py", line 331, in readline
buf += self._read_timeout(timeout)
File "C:\environments\democracy\lib\site-packages\paramiko\packet.py", line 485, in _read_timeout
x = self.__socket.recv(128)
File "C:\environments\democracy\lib\site-packages\gevent\_socket3.py", line 317, in recv
self._wait(self._read_event)
File "C:\environments\democracy\lib\site-packages\gevent\_socket3.py", line 144, in _wait
self.hub.wait(watcher)
File "C:\environments\democracy\lib\site-packages\gevent\hub.py", line 630, in wait
result = waiter.get()
File "C:\environments\democracy\lib\site-packages\gevent\hub.py", line 878, in get
return self.hub.switch()
File "C:\environments\democracy\lib\site-packages\gevent\hub.py", line 609, in switch
return greenlet.switch(self)
gevent.hub.LoopExit: ('This operation would block forever', <Hub at 0x242566ab9c8 select pending=0 ref=0>)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\environments\democracy\lib\site-packages\paramiko\transport.py", line 1740, in run
self._check_banner()
File "C:\environments\democracy\lib\site-packages\paramiko\transport.py", line 1888, in _check_banner
raise SSHException('Error reading SSH protocol banner' + str(e))
paramiko.ssh_exception.SSHException: Error reading SSH protocol banner('This operation would block forever', <Hub at 0x242566ab9c8 select pending=0 ref=0>)
General SSH error - Error reading SSH protocol banner('This operation would block forever', <Hub at 0x242566ab9c8 select pending=0 ref=0>)
如果我在 fabric 之前导入 pssh,上面的代码可以工作。不幸的是,如果我这样做,我的 kivy 界面上的任何按钮(启动后台线程中的任何操作)都会在按下时永远阻塞。如果我在按下按钮后进入控制台并发送键盘中断,kivy 将停止阻塞并开始清理,但在退出之前执行按钮按下的命令。发送此中断的堆栈跟踪如下:
[INFO ] [Base ] Leaving application in progress...
Traceback (most recent call last):
File "machine_control_ui.py", line 7, in <module>
DemocracyControllerApp().run()
File "C:\environments\democracy\lib\site-packages\kivy\app.py", line 828, in run
runTouchApp()
File "C:\environments\democracy\lib\site-packages\kivy\base.py", line 504, in runTouchApp
EventLoop.window.mainloop()
File "C:\environments\democracy\lib\site-packages\kivy\core\window\window_sdl2.py", line 659, in mainloop
self._mainloop()
File "C:\environments\democracy\lib\site-packages\kivy\core\window\window_sdl2.py", line 405, in _mainloop
EventLoop.idle()
File "C:\environments\democracy\lib\site-packages\kivy\base.py", line 339, in idle
Clock.tick()
File "C:\environments\democracy\lib\site-packages\kivy\clock.py", line 553, in tick
current = self.idle()
File "C:\environments\democracy\lib\site-packages\kivy\clock.py", line 533, in idle
usleep(1000000 * sleeptime)
File "C:\environments\democracy\lib\site-packages\kivy\clock.py", line 717, in usleep
_usleep(microseconds, self._sleep_obj)
File "C:\environments\democracy\lib\site-packages\kivy\clock.py", line 395, in _usleep
_kernel32.WaitForSingleObject(obj, 0xffffffff)
KeyboardInterrupt
*** BUTTON PRESS OPERATION OUTPUTS HERE ***
```
任何关于为什么会发生这种情况以及如何避免这种情况的见解将不胜感激。我可能会研究其他并行 ssh 解决方案(尽管我认为使用 paramiko 的任何东西都会有同样的问题),或者手动启动每个主机的线程以实现并行操作(这可能有自己的头痛列表),但我如果有可行的解决方案,我宁愿只使用 parallel-ssh 库。
我在 Python 3 和 Windows 10 上使用 parallel-ssh 0.92.2。
【问题讨论】:
【参考方案1】:来自docs -
parallel-ssh 使用 gevent 的猴子补丁来启用异步使用 Python 标准库的网络 I/O。
确保 ParallelSSH 导入在任何其他导入之前 你的代码。否则可能无法在标准前打补丁 库已加载,这将导致 ParallelSSH 阻塞。
如果您看到类似“此操作将永远阻塞”的消息, 这就是原因。
Monkey 补丁只针对 pssh.pssh_client 下的客户端进行 和 pssh.ssh_client 分别用于并行和单主机客户端。
在 pssh.pssh2_client 和 pssh.ssh2_client 不执行猴子补丁并且是一个选项,如果 猴子补丁不适合。这些客户端将成为默认客户端 在未来的主要版本中 - 2.0.0。
由于猴子补丁用于您正在使用的客户端,因此您的应用程序中threading
、socket
等模块的其他用途也将被修补为使用 gevent,这意味着它们不再在本机线程中运行,而是在协同程序/greenlet中。
这就是您的后台线程操作阻塞的原因,因为它们在同一线程而不是新线程上的 greenlet 中运行。
从1.2.0
开始,一个基于libssh2
而不是 paramiko 的新客户端可用,它不使用猴子补丁:
from pssh.pssh2_client import ParallelSSHClient
<..>
然后您的应用程序的其余部分可以按原样使用标准库。
【讨论】:
以上是关于一般 SSH 错误 - 读取 SSH 协议横幅时出错的主要内容,如果未能解决你的问题,请参考以下文章
解决 FileZilla 20秒连接超时问题. (SSH + sftp协议)