您好我在执行一个通过Ubuntu 10服务器执行100mb文件的wget的命令时遇到问题。除此之外,较短的命令工作正常。下面的类包含我如何使用paramiko和我克服这个问题的不同尝试(请参阅不同的run或exec方法)。在exec_cmd的情况下,执行挂起在这一行:
out = self.in_buffer.read(nbytes, self.timeout)
来自paramiko的channel.py模块的recv方法。
使用Mac中的普通ssh实用程序,相同的wget命令在shell中完美运行。
"""
Management of SSH connections
"""
import logging
import os
import paramiko
import socket
import time
import StringIO
class SSHClient():
def __init__(self):
self._ssh_client = paramiko.SSHClient()
self._ssh_client.load_system_host_keys()
self._ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
self.time_out = 300
self.wait = 5
def connect(self, hostname, user, pkey):
retry = self.time_out
self.hostname = hostname
logging.info("connecting to:%s user:%s key:%s" % (hostname, user, pkey))
while retry > 0:
try:
self._ssh_client.connect(hostname,
username=user,
key_filename=os.path.expanduser(pkey),
timeout=self.time_out)
return
except socket.error, (value,message):
if value == 61 or value == 111:
logging.warning('SSH Connection refused, will retry in 5 seconds')
time.sleep(self.wait)
retry -= self.wait
else:
raise
except paramiko.BadHostKeyException:
logging.warning("%s has an entry in ~/.ssh/known_hosts and it doesn't match" % self.server.hostname)
logging.warning('Edit that file to remove the entry and then try again')
retry = 0
except EOFError:
logging.warning('Unexpected Error from SSH Connection, retry in 5 seconds')
time.sleep(self.wait)
retry -= self.wait
logging.error('Could not establish SSH connection')
def exists(self, path):
status = self.run('[ -a %s ] || echo "FALSE"' % path)
if status[1].startswith('FALSE'):
return 0
return 1
def shell(self):
"""
Start an interactive shell session on the remote host.
"""
channel = self._ssh_client.invoke_shell()
interactive_shell(channel)
def run(self, command):
"""
Execute a command on the remote host. Return a tuple containing
an integer status and a string containing all output from the command.
"""
logging.info('running:%s on %s' % (command, self.hostname))
log_fp = StringIO.StringIO()
status = 0
try:
t = self._ssh_client.exec_command(command)
except paramiko.SSHException:
logging.error("Error executing command: " + command)
status = 1
log_fp.write(t[1].read())
log_fp.write(t[2].read())
t[0].close()
t[1].close()
t[2].close()
logging.info('output: %s' % log_fp.getvalue())
return (status, log_fp.getvalue())
def run_pty(self, command):
"""
Execute a command on the remote host with a pseudo-terminal.
Returns a string containing the output of the command.
"""
logging.info('running:%s on %s' % (command, self.hostname))
channel = self._ssh_client.get_transport().open_session()
channel.get_pty()
status = 0
try:
channel.exec_command(command)
except:
logging.error("Error executing command: " + command)
status = 1
return status, channel.recv(1024)
def close(self):
transport = self._ssh_client.get_transport()
transport.close()
def run_remote(self, cmd, check_exit_status=True, verbose=True, use_sudo=False):
logging.info('running:%s on %s' % (cmd, self.hostname))
ssh = self._ssh_client
chan = ssh.get_transport().open_session()
stdin = chan.makefile('wb')
stdout = chan.makefile('rb')
stderr = chan.makefile_stderr('rb')
processed_cmd = cmd
if use_sudo:
processed_cmd = 'sudo -S bash -c "%s"' % cmd.replace('"', '\\"')
chan.exec_command(processed_cmd)
result = {
'stdout': [],
'stderr': [],
}
exit_status = chan.recv_exit_status()
result['exit_status'] = exit_status
def print_output():
for line in stdout:
result['stdout'].append(line)
logging.info(line)
for line in stderr:
result['stderr'].append(line)
logging.info(line)
if verbose:
print processed_cmd
print_output()
return exit_status,result
def exec_cmd(self, cmd):
import select
ssh = self._ssh_client
channel = ssh.get_transport().open_session()
END = "CMD_EPILOGqwkjidksjk58754dskhjdksjKDSL"
cmd += ";echo " + END
logging.info('running:%s on %s' % (cmd, self.hostname))
channel.exec_command(cmd)
out = ""
buf = ""
while END not in buf:
rl, wl, xl = select.select([channel],[],[],0.0)
if len(rl) > 0:
# Must be stdout
buf = channel.recv(1024)
logging.info(buf)
out += buf
return 0, out
答案 0 :(得分:2)
+=
时,您基本上都会创建两个新字符串并读取第三个字符串。另一方面,如果创建一个列表并附加它,则将创建的字符串数量减半。select
或多或少是同名C方法的包装器:
select()和pselect()允许程序监视多个文件描述符,等待一个或多个文件描述符变为“准备好”某类I / O操作(例如,输入可能)。文件描述符是con 如果可以在不阻塞的情况下执行相应的I / O操作(例如,读取(2)),则备用就绪。
socket.timeout
异常。recv
返回的每一行。你能移动日志线吗?try:
out = self.in_buffer.read(nbytes, self.timeout)
except PipeTimeout, e:
# do something with error
不保证,但会减少额外处理。
答案 1 :(得分:2)
我遇到了同样的问题,当我在远程ssh客户端上运行shell脚本时,我的python脚本挂起,在400Mb文件上执行了wget命令。
我发现在wget命令中添加超时可以解决问题。 原来我有:
wget http://blah:8888/file.zip
现在用这个:
wget -q -T90 http://blah:8888/file.zip
它就像一个魅力!
希望它有所帮助。