Ftplib storbinary с FTPS зависает / не завершается

Я пытаюсь загрузить файл на FTP-сайт с помощью FTPS, но когда я пытаюсь сохранить файл, он просто зависает после полной передачи файла.

global f_blocksize
global total_size
global size_written
f_blocksize = 1024
total_size = os.path.getsize(file_path)
size_written = 0
file = open(file_path, "rb")
try:
    ftps = FTP_TLS("ftp.example.com")
    ftps.auth()
    ftps.sendcmd("USER username")
    ftps.sendcmd("PASS password")
    ftps.prot_p()
    print(ftps.getwelcome())

    try:
        print("File transfer started...")
        ftps.storbinary("STOR myfile.txt", file, callback=handle, blocksize=f_blocksize)
        print("File transfer complete!")
    except OSError as ex:
        print(ftps.getresp())
except Exception as ex:
    print("FTP transfer failed.")
    print("%s: %s" %(type(ex), str(ex)))

def handle(block):
    global size_written
    global total_size
    global f_blocksize
    size_written = size_written + f_blocksize if size_written + f_blocksize < total_size else total_size
    percent_complete = size_written / total_size * 100
    print("%s percent complete" %str(percent_complete))

Получаю следующий результат:

220 Microsoft FTP Service
File transfer started...
3.5648389904264577 percent complete
7.129677980852915 percent complete
10.694516971279374 percent complete
14.25935596170583 percent complete
17.824194952132288 percent complete
21.389033942558747 percent complete
24.953872932985206 percent complete
28.51871192341166 percent complete
32.083550913838124 percent complete
35.648389904264576 percent complete
39.213228894691035 percent complete
42.778067885117494 percent complete
46.342906875543946 percent complete
49.90774586597041 percent complete
53.472584856396864 percent complete
57.03742384682332 percent complete
60.60226283724979 percent complete
64.16710182767625 percent complete
67.7319408181027 percent complete
71.29677980852915 percent complete
74.8616187989556 percent complete
78.42645778938207 percent complete
81.99129677980854 percent complete
85.55613577023499 percent complete
89.12097476066144 percent complete
92.68581375108789 percent complete
96.25065274151436 percent complete
99.81549173194082 percent complete
100.0 percent complete

После этого нет дальнейшего прогресса, пока не истечет время ожидания соединения ...

FTP transfer failed.
<class 'ftplib.error_temp'>: 425 Data channel timed out due to not meeting the minimum bandwidth requirement.

Во время работы программы я вижу пустой myfile.txt на FTP-сайте, если я подключаюсь и смотрю вручную, но когда я либо отменяю его, либо время ожидания соединения истекает, этот пустой файл исчезает.

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

Да, я могу загружать файлы с помощью Filezilla. Нет, это происходит только с FTPS. Да, такая же ошибка при опущении параметров callback и blocksize из storbinary. Я перешел на login, но это все еще происходит.

ryansin 02.05.2018 09:13

Это простейший код, воспроизводящий ошибку. Это не мой сервер, поэтому я не могу предоставить журналы сервера. Однако я заметил, что когда я запускаю его на своем собственном FTP-сервере, он работает нормально.

ryansin 02.05.2018 09:20
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
3
2
1 642
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Похоже, это проблема класса SSLSocket Python, который ожидает данных от сервера при запуске unwrap. Поскольку он никогда не получает эти данные от сервера, он не может развернуть SSL из сокета и, следовательно, истекает время ожидания.

Этот сервер, в частности, я определил в приветственном сообщении как какой-то FTP-сервер Microsoft, что хорошо согласуется с проблемой, описанной в этот блог.

«Исправление» (если его можно так назвать) состояло в том, чтобы остановить SSLSocket от попыток полностью развернуть соединение, отредактировав ftplib.py и изменив метод FTP_TLS.storbinary().

def storbinary(self, cmd, fp, blocksize=8192, callback=None, rest=None):
  self.voidcmd('TYPE I')
  with self.transfercmd(cmd, rest) as conn:
    while 1:
      buf = fp.read(blocksize)
      if not buf: break
      conn.sendall(buf)
      if callback: callback(buf)
    # shutdown ssl layer
    if isinstance(conn, ssl.SSLSocket):
      # HACK: Instead of attempting unwrap the connection, pass here
      pass
  return self.voidresp()

Другие вопросы по теме