请告诉我为什么会出现这种死锁:从 Paramiko exec_command() file-like objects 读取和写入 -- ChannelFile.close() 不起作用

Please tell me why this deadlocks: Reading and writing from Paramiko exec_command() file-like objects -- ChannelFile.close() does not work

import paramiko, threading

def Reader(src):
    while True:
        data = src.readline()
        if not data: break
        print data


client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect("172.17.0.2", username="test", password="test")

stdin, stdout, stderr = client.exec_command("dd of=readme.txt")

reader = threading.Thread(target=Reader, args=(stderr, ))
reader.start()

stdin.write("some data")
stdin.flush()
stdin.close()

reader.join()

此代码在 join() 处永远等待。如果我删除 stderr 写入线程,它会按预期工作,将正确的文本写入文件 'readme.txt',但我会丢失 dd stderr 消息。

问题出在stdin.close()。根据 Paramiko 的文档 (v1.16):

Warning: To correctly emulate the file object created from a socket’s makefile() method, a Channel and its ChannelFile should be able to be closed or garbage-collected independently. Currently, closing the ChannelFile does nothing but flush the buffer.

所以你必须使用stdin.channel.close().


更新:

由于 stdinstdoutstderr 都共享一个通道,stdin.channel.close() 也会关闭 stderr 所以你的 Reader 线程可能什么也得不到。解决方案是使用 stdin.channel.shutdown_write(),它不允许写入通道但仍然允许从通道读取。

验证它工作正常:

[STEP 101] # cat foo.py
import paramiko, threading, paramiko

def Reader(src):
    while True:
        data = src.read()
        if not data: break
        print data,

client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect("10.11.12.13", username="root", password="password")

stdin, stdout, stderr = client.exec_command("dd of=/tmp/file")

reader = threading.Thread(target=Reader, args=(stderr,) )
reader.start()

stdin.write("some data")
stdin.flush()
stdin.channel.shutdown_write()

reader.join()
[STEP 102] # python foo.py
0+1 records in
0+1 records out
[STEP 103] #