1

I'm trying to make Python uploading files on a FTP server. The code is following:

... ## setting values to variables: ftp_site, ftp_port, ftp_user, ftp_pwd, output_file_name, output_file
import ftplib
ftps = ftplib.FTP_TLS()
ftps.connect(ftp_site,ftp_port)
ftps.auth()
ftps.login(ftp_user,ftp_pwd)
ftps.prot_p()
ftps.storbinary("STOR " + output_file_name,open(output_file,'rb'))
ftps.quit()

It used to work fine earlier, but now I get the following error:

error: [Errno 10054] An existing connection was forcibly closed by the remote host

I get the error on the line

ftps.storbinary("STOR " + output_file_name,open(output_file,'rb'))

The Python version is 2.7. I've been looking through similar topics but nothing helps. Could anyone tell how to make it work please?

I can upload a file from this machine to the server using through TCM/FileZilla. Moreover, I can rename a file on the server using Python with this command:

ftps.rename('a.txt', 'b.txt')

So that's not an access issue.

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
Dmitriy
  • 37
  • 4

2 Answers2

1

I think the issue lies in that you are trying to connect to an insecure FTP server using FTP over TLS. The code you provided has been tested with an insecure FTP server over port 21, and the same exact error is thrown. If that's the case, please try using instead the below. Please note, the below establishes an insecure connection between you and the FTP server.

import ftplib

hostname = '127.0.0.1'
username = 'admin'
password = ''

ftp = ftplib.FTP(hostname, username, password)
file = open('image.png','rb')
output_file_name = "image.png"
ftp.storbinary("STOR " + output_file_name, file)
file.close()                                    
ftp.quit()

Update 1

This update shows how to reprocduce the error the questioner is referring to, i.e., "An existing connection was forcibly closed by...", as well as the following behaviour: "I can rename a file on the server using Python with this command: ftps.rename('a.txt', 'b.txt')". The following steps are on a windows machine, but shouldn't be that different on other systems as well.

First, download and install FileZilla server on your machine. Start the server and go to the Administration Interface. From there, navigate to "Server" in the file menu and then click on "Configure...". Under "Users" make sure you have an "admin" user with blank password (for the purposes of this demo) and a folder (point) mounted serving as the FTP directory. Within that folder create a txt file named "a.txt" (doesn't need to have any contents). Make sure your server is up and running on port 21.

Now, for the FTP client, create a python file and paste the following code. Make sure you create a txt file named "hello.txt" in the same directory as the python file, with some text inside, e.g., "Hello World!". Next, run the python file (FTP cLient). You will notice that an error is thrown at line 9 ftps.storbinary("STOR " + output_file_name, open('hello.txt','rb')), saying "...An existing connection was forcibly closed by the remote host". Having a look now at the FTP directory of your server, you will see that the file named "a.txt" has been renamed to "b.txt", while there is also a file named "hello.txt", however, without any contents inside (i.e., empty file).

PS: If you are going to rerun the client, remember to rename the "b.txt" file in the FTP directory back to its original name ("a.txt"), otherwise an error will be thrown when attempting to rename it from the client.

import ftplib
ftps = ftplib.FTP_TLS()
ftps.connect("127.0.0.1", 21)
ftps.auth()
ftps.login("admin","")
ftps.prot_p()
ftps.rename('a.txt', 'b.txt')
output_file_name = "hello.txt"
ftps.storbinary("STOR " + output_file_name, open('hello.txt','rb'))
ftps.quit()

Update 2

Although the above explains how to reproduce the issue described by the original poster, it does not solve the issue in any way. As it turns out (and correctly pointed out by @Martin Prikryl), the latest version of FileZilla server has TLS enabled by default, meaning that with the above code sample, the client does connect to an FTP over TLS server. Thus, the issue remains and probably lies elsewhere. The answer will remain posted in case future readers benefit from it, or in case the author returns with new info on the issue.

Chris
  • 18,724
  • 6
  • 46
  • 80
  • If you connect to an insecure server, you won't get to the `storbinary`. It will fail earlier, even in maybe in some cases with the same error (but more likely with dozen different encryption-related errors). – Martin Prikryl Jan 27 '22 at 09:18
  • Connecting with the OP's code to an FTP server that does not support TLS will fail at the `auth` call. Tested now (not that I needed to). – Martin Prikryl Jan 27 '22 at 10:48
  • But that's not TLS issue as such. The latest version of FileZilla server has TLS always on (so it's not true that you are connecting to a server that does not support it, quite on the contrary). Otherwise you would not make it past the `auth`. If you check FileZilla log, I'm sure you will see *"TLS session of data connection not resumed"* – If you see that, you have this issue: [FTPS with Python ftplib - Session reuse required](https://stackoverflow.com/q/14659154/850848). – But that's still a different issue than what variable has (as he/she get the error only at the end of the transfer). – Martin Prikryl Jan 27 '22 at 13:26
  • That's true, thanks. I have updated the answer with the relevant info. I'll leave it posted for now in case it can be of benefit to anyone, or in case I get back to it later. Hard to believe that this issue has still not been resolved. – Chris Jan 27 '22 at 16:28
  • 1
    It's still possible that the *OP* did have the *"TLS session reuse"* problem though. So maybe after all, we have come to a useful conclusion. – Martin Prikryl Jan 27 '22 at 19:23
-1
import ftplib
session = ftplib.FTP('server.address.com','USERNAME','PASSWORD')
file = open('kitten.jpg','rb')                  # file to send
session.storbinary('STOR kitten.jpg', file)     # send the file
file.close()                                    # close file and FTP
session.quit()

And to retrive use this:

import urllib 

urllib.urlretrieve('ftp://server/path/to/file', 'file')