Почему Paramiko вызывает EOFError (), когда объект SFTP хранится в словаре? - PullRequest
7 голосов
/ 17 марта 2011

У меня возникли проблемы с приложением, которое я пишу, которое загружает и загружает файлы в другие коробки через SSH. Проблема, с которой я сталкиваюсь, заключается в том, что я могу нормально получать (загружать) файлы, но когда я пытаюсь поместить (загружать) их на другой сервер, я получаю исключение EOFError (). Когда я посмотрел на _write_all () в paramiko \ sftp.py, мне показалось, что ошибка была вызвана тем, что он не мог записать данные в поток? У меня нет опыта сетевого программирования, поэтому, если кто-то знает, что он пытается сделать, и может сообщить мне об этом, я буду признателен.

Я написал упрощенную версию функции, которая обрабатывает мои соединения, как ssh (). runCommand () показывает, как происходит сбой загрузки в моем приложении, а simpleTest () показывает, как работает sftp put, но я не вижу никакой разницы между runCommand () и simpleTest (), кроме того, как хранятся мои объекты SFTP. Один хранится в словаре, а другой сам по себе. Кажется, если бы в словаре была проблема, что загрузка файлов не работала бы, но это не так.

Кто-нибудь знает, что может вызвать такое поведение, или мог бы порекомендовать другой способ управления моими соединениями, если этот способ вызывает проблемы?

Я использую Python 2.7 с Paramiko 1.7.6. Я протестировал этот код на Linux и Windows и получил те же результаты.

РЕДАКТИРОВАТЬ: код включен сейчас.

import os
import paramiko

class ManageSSH:
     """Manages ssh connections."""
    def __init__(self):
        self.hosts = {"testbox": ['testbox', 'test', 'test']}
        self.sshConnections = {}
        self.sftpConnections = {}
        self.localfile = "C:\\testfile"
        self.remotefile = "/tmp/tempfile"
        self.fetchedfile = "C:\\tempdl"

    def ssh(self):
        """Manages ssh connections."""
        for host in self.hosts.keys():
            try:
                self.sshConnections[host]
                print "ssh connection is already open for %s" % host
            except KeyError, e:         # if no ssh connection for the host exists then open one
                # open ssh connection
                ssh = paramiko.SSHClient()
                ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
                ssh.connect(self.hosts[host][0], 22, self.hosts[host][1], self.hosts[host][2])
                self.sshConnections[host] = ssh
                print "ssh connection to %s opened" % host
            try:
                self.sftpConnections[host]
                print "sftp connection is already open for %s" % host
            except KeyError, e:
                # open sftp connection
                ssh = paramiko.SSHClient()
                ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
                ssh.connect(self.hosts[host][0], 22, self.hosts[host][1], self.hosts[host][2])
                self.sftpConnections[host] = ssh.open_sftp()
                print "sftp connection to %s opened" % host

    def runCommand(self):
        """run commands and return output"""
        for host in self.hosts:
            command = "if [ -d /tmp ]; then echo -n 1; else echo -n 0; fi"
            stdin, stdout, stderr = self.sshConnections[host].exec_command(command)
            print "%s executed on %s" % (command, host)
            print "returned %s" % stdout.read()
            self.sftpConnections.get(self.remotefile, self.fetchedfile)
            print "downloaded %s from %s" % (self.remotefile, host)
            self.sftpConnections[host].put(self.localfile, self.remotefile)
            print "uploaded %s to %s" % (self.localfile, host)
            self.sftpConnections[host].close()
            self.sshConnections[host].close()

    def simpleTest(self):
        host = "testbox"
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh.connect(host, 22, 'test', 'test')
        sftp = ssh.open_sftp()
        print "sftp connection to %s opened" % host
        sftp.get(self.remotefile, self.fetchedfile)
        print "downloaded %s from %s" % (self.localfile, host)
        sftp.put(self.localfile, self.remotefile)
        print "uploaded %s to %s" % (self.localfile, host)
        sftp.close()

if __name__ == "__main__":
    test = ManageSSH()
    print "running test that works"
    test.simpleTest()
    print "running test that fails"
    test.ssh()
    test.runCommand()

выход:

running test that works
sftp connection to testbox opened
downloaded C:\testfile from testbox
uploaded C:\testfile to testbox
running test that fails
ssh connection to testbox opened
sftp connection to testbox opened
if [ -d /tmp ]; then echo -n 1; else echo -n 0; fi executed on testbox
returned 1
downloaded /tmp/tempfile from testbox
Traceback (most recent call last):
  File "paramikotest.py", line 71, in <module>
    test.runCommand()
  File "paramikotest.py", line 47, in runCommand
    self.sftpConnections[host].put(self.localfile, self.remotefile)
  File "C:\Python27\lib\site-packages\paramiko\sftp_client.py", line 561, in put

    fr = self.file(remotepath, 'wb')
  File "C:\Python27\lib\site-packages\paramiko\sftp_client.py", line 245, in open
    t, msg = self._request(CMD_OPEN, filename, imode, attrblock)
  File "C:\Python27\lib\site-packages\paramiko\sftp_client.py", line 627, in _request
    num = self._async_request(type(None), t, *arg)
  File "C:\Python27\lib\site-packages\paramiko\sftp_client.py", line 649, in _async_request
    self._send_packet(t, str(msg))
  File "C:\Python27\lib\site-packages\paramiko\sftp.py", line 172, in _send_packet
    self._write_all(out)
  File "C:\Python27\lib\site-packages\paramiko\sftp.py", line 138, in _write_all

    raise EOFError()
EOFError

Ответы [ 3 ]

7 голосов
/ 12 августа 2011

Мне удалось решить мою проблему. Я должен был использовать Paramiko.Transport, а затем создать SFTPClient с paramiko.SFTPClient.from_transport(t) вместо использования open_sftp() из SSHClient().

Работает следующий код:

t = paramiko.Transport((host, 22))  
t.connect(username=username, password=password)  
sftp = paramiko.SFTPClient.from_transport(t)
2 голосов
/ 24 февраля 2013

как я вижу, с помощью ssh = SSHClient () вы создаете объект SSHClient, а затем с помощью sftp = ssh.open_sftp () вы создаете объект sftp.в то время как вы хотите использовать только sftp, вы сохраняете ssh в локальной переменной, которая затем получает gc'd, но, если ssh - gc'd, sftp волшебным образом перестает работать.не знаю почему, но попробуйте сохранить ssh на время жизни вашего sftp.

0 голосов
/ 21 марта 2011

После прочтения вашего редактирования я думаю, что проблема здесь

stdin, stdout, stderr = self.sshConnections[host].exec_command(command)

эта строка, очевидно, отключает ftp вещь

EDITED

...