Paramiko官网文档链接: http://docs.paramiko.org/en/stable/
一、执行指令路径
exec_command是在登录时默认路径下执行命令,且每次执行都是在登录时的默认路径下执行命令,即使执行了client.exec_command('cd XXX'),再执行下一条指令时,仍然在登录时的默认路径。
要规避该问题有三种方法
1、每次与路径相关的指令用绝对路径
2、一条字符串包含多条指令,指令间用分号间隔,一起传递。
client.exec_command('cd /home/; ls -al')
3、交互式编程,通过invoke_shell开启一个会话,然后用会话的send,recv方法分别发送和接收指令。
二、SFTP传递文件情况实时监测
当SFTP需要发送或接收的文件较大时,传递时间较长,等待过程中需要提示文件传递情况。
注意put方法中的callback,可以定义一个回调函数,以实时检测文件传递情况。
put
(localpath, remotepath, callback=None, confirm=True)
Copy a local file (localpath
) to the SFTP server as remotepath
. Any exception raised by operations will be passed through. This method is primarily provided as a convenience.
The SFTP operations use pipelining for speed.
Parameters: |
|
---|
sftp_client.put(src_file, dst_file,callback=self.PutCallback)
回调函数调用的非常频繁,具体时间未测试。为减少提示次数,定义每增加5%提示一次。
def PutCallback(self,TransferredSize, ToBeTransferred):
rate = int(TransferredSize * 100 / ToBeTransferred)
if rate > self.percent + 5:
self.percent = rate
三、执行指令持续输出
https://stackoverflow.com/questions/25260088/paramiko-with-continuous-stdout
stdin, stdout, stderr = client.exec_command(str_command) #str_command为需要执行的指令
for l in self.line_buffered(stdout): #stdout为持续输出的结果,l为结果的每一行。如果行中包含update_prog_percent则输出给界面显示
if "update_prog_percent" in l:
self.MsgSigOut.emit(addr + l, 1)
self.log.info(addr + l)
def line_buffered(self, f): #每读取一行执行结果就输出一行
line_buf = ""
while not f.channel.exit_status_ready():
line_buf += f.read(1).decode('utf8')
if line_buf.endswith('\n'):
yield line_buf
line_buf = ''
四、Client、Channel、Transport的关系
SSHClient表示与SSH server会话的高层表示,封装了Transport、Channel和SFTPClient。在SSHClient源代码中可以看到其包含了一个transport作为私有变量,通过transport创建出channel后在channel执行exec_command和invoke_shell。
Transport像一个流而不是像socket,它协商了加密会话,鉴权并创建了流的隧道控制,也即channel。许多的channel通过一个会话复用。(通常在端口转发(port forwarding)模式下)。
端口转发(port forwarding)原理见下文:
https://www.cnblogs.com/kidsitcn/p/11090252.html
一个Channel与一个socket类似,其API与Python socket API完全一致。SSH2有一个类似滑动窗口的流控机制,如果客户端停止从Channel读取,并且Channel的buffer满了,则服务器不能再向客户端发送数据直到客户端读取了数据。(这不会影响同一个transport下面其他channel的流控,同一个transport下面的channel都是独立进行流控的)。类似的,如果服务器不及时读取客户端发送的数据,客户端发送数据将会出现阻塞,除非客户端设置了超时机制。
exec_command在服务器执行命令,如果服务器允许执行,命令执行后channel立即连接到stdin、stdout和stderr。
exec_command命令执行完后,channel会关闭并且不再使用,如果要执行其他命令需要重新打开一个channel。
invoke_shell在channel上获取一个交互式shell会话。如果服务器允许,channel将连接到stdin、stdout和stderr。
在invoke_shell之前一般需要调用get_pty创建伪终端,channel连接到伪终端的stdin、stdout和stderr。
当shell退出时,channel会关闭并且不再被使用。如果想打开领一个shell需要打开一个新的channel。
get_pty从服务器获取一个伪终端,这通常在创建client channel之后,请求服务器为invoke_shell创建的shell提供服务。如果只是通过exec_command执行单个指令则不需要调用该方法。