gpt4 book ai didi

python - 标准错误上的 Paramiko recv()/read()/readline(s)() 返回空字符串

转载 作者:行者123 更新时间:2023-12-04 18:01:58 26 4
gpt4 key购买 nike

我正在使用 paramiko 收集有关远程主机的一些信息并遇到问题,在读取 (read()/readline()/readlines( )) 来自 stderr channel 。

有时 stderr.read() 会返回一个空字符串,对我来说这看起来像是竞争条件的结果。但是,根据我在 Internet 上找到的文档和示例,这似乎是正确的方法。

我还尝试打开一个专用 channel 并利用 chan.recv_ready()/chan.recv_stderr_ready() 并通过循环从各个 channel 读取 chan.recv()/chan.recv_stderr() 但是会导致相同的行为。

这是一个最小的测试用例 - 在我的设置中 - 可靠地导致了该行为。

import paramiko

class SSH:
def __init__(self):
self.ssh = paramiko.SSHClient()
self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
self.ssh.connect('127.0.0.1', port=31337, username='root', password='root')

self.stdout = ''
self.stderr = ''
self.exit_code = 0

def _run_cmd(self, cmd):
self.stdout = ''
self.stderr = ''

stdin, stdout, stderr = self.ssh.exec_command(cmd)

self.stdout = stdout.read()
self.stderr = stderr.read()

while not stdout.channel.exit_status_ready():
pass
self.exit_code = stdout.channel.recv_exit_status()

if self.exit_code:
print("ERROR: " + self.stderr)

def process_list(self):
self._run_cmd('ls /proc/ | grep -E "^[0-9]+$" | grep -v $$')
lines = self.stdout.split('\n')[:-1]
data = []

for process in lines:
process_data = {}
process_data['pid'] = int(process)

# fetching and parsing process status information from /proc/[PID]/status

self._run_cmd('cat /proc/%d/status' % (int(process)))

data.append(self.stdout)

return data


data = SSH()
while True:
print data.process_list()

经过几次运行(如果不是第一次)我得到的是:
错误:
虽然我期待:
错误:cat:/proc/12883/status:没有那个文件或目录

如何确保 stderr 已准备好读取/我读取了 stderr 上的所有数据?

最佳答案

长话短说:我遇到过这些问题中的大多数,并且针对我的大多数 ssh 相关问题提出了最终解决方案。因此,请随时查看 this exec_command 的实现避免了大多数 empty_response/stalling 场景。

说来话长

这里的主要问题是您的 exec_command() 是非阻塞的,并且生成一个负责 channel 通信的线程。该线程正在等待传入数据并将其放入 channel 缓冲区,而主线程可能会继续运行。这就是你的问题所在。您读取缓冲区的时间过早,甚至在您检查您的一方是否收到 exit_status 之前。收到 exit_status 确认远程进程以给定的状态代码退出。收到远程状态代码并不表示您已收到可能仍在传输中的所有数据。它甚至可能乱序到达你身边,说 status_code 可能甚至在所有数据之前到达(stderr,stdout)收到了。

当数据到达时,主线程继续。在您的情况下,主线程尝试从 stdoutstderr 读取一次,然后阻塞直到 exit_status 准备就绪。请注意, channel 线程可能仍会从您的远程命令调用接收数据。另请注意,一旦您的一方收到远程 exit_status,您将必须手动清空缓冲区。

在您的特定情况下,会发生这种情况:

  1. execute_command 生成一个新线程(调用 id exec_thread,管理远程命令调用
  2. 虽然最近生成的线程可能会收到数据,但主线程会继续运行。
  3. [main-thread] 您正在将stdoutstderr 缓冲区的当前 内容存储在self.stdout,self.stderr。请注意,您不知道是否收到了 stderrstdout 的所有数据。您很可能刚刚收到了一些 block 。
  4. [exec_thread] 愉快地为 stdoutstderr 接收数据,而 [main-thread] 继续。
  5. [main-thread] 忙阻塞,直到收到 exit_status。再次注意,此时您的缓冲区可能仍然充满了最近收到的 stderrstdout block 。
  6. [main-thread] exit_status 存储在self.exit_code 中。 [exec_thread] 仍然存在,可能仍会收到一些乱序数据。输入缓冲区可能仍处于填充状态。
  7. [主线程] 从 run_cmd 返回

请注意,该 channel 的 [exec_thread] - paramiko 为每个 channel 调用创建一个线程(即 exec_command) - 仍然存在,它们会一直闲置并产生问题,直到您手动关闭它们(stdout.channel.close()).

关于python - 标准错误上的 Paramiko recv()/read()/readline(s)() 返回空字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33708336/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com