在 Python 中使用 ftplib 将文件传输到 FTP 服务器时获取 "Connection refused"

Getting "Connection refused" when transferring a file to FTP server with ftplib in Python

我目前正在编写一个 python 脚本来将文本文件上传到 FTP 服务器,但我收到以下错误 ConnectionRefusedError: [Errno 61] Connection refused,我这辈子都不能'似乎没有弄清楚这个问题。我认为这要么是 FTP 服务器的问题(我可以通过 FileZilla 使用相同的凭据连接到它)。这让我相信这可能是一个编码问题,但经过大量研究,一切看起来都是正确的。所以我决定,违背我更好的判断,跪下来寻求帮助。即使该帮助只是确定问题出在服务器上而不是我的代码上。这至少会给我下一个故障排除的地方。

提前感谢您提供的任何见解!

代码如下:

import ftplib

def ftp_upload(ftp_obj, path, ftype='TXT'):
    """
    A function for uploading files to an FTP server
    @param ftp_obj: The file transfer protocol object
    @param path: The path to the file to upload
    """
    if ftype == 'TXT':
        with open(path) as fobj:
            ftp.storlines('STOR ' + path, fobj)
    else:
        with open(path, 'rb') as fobj:
            ftp.storbinary('STOR ' + path, fobj, 1024)

if __name__ == '__main__':
    ftp = ftplib.FTP(host='domain or i.p. address')
    ftp.login(user = 'username', passwd = 'password')

    path = input('Please provide path to file: ')
    ftp_upload(ftp, path)

    pdf_path = '/path/to/something.pdf'
    ftp_upload(ftp, pdf_path, ftype='PDF')

    ftp.quit()

这是完整的回溯:

Traceback (most recent call last):
File "ftp_text_file.py", line 21, in <module>
ftp_upload(ftp, path)
File "ftp_text_file.py", line 11, in ftp_upload
ftp.storlines('STOR ' + path, fobj)
File   "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/ftplib.py", line 528, in storlines
with self.transfercmd(cmd) as conn:
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/ftplib.py", line 397, in transfercmd
return self.ntransfercmd(cmd, rest)[0]
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/ftplib.py", line 359, in ntransfercmd
source_address=self.source_address)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/socket.py", line 722, in create_connection
raise err
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/socket.py", line 713, in create_connection
sock.connect(sa)
ConnectionRefusedError: [Errno 61] Connection refused

更新: 提供了 FileZilla 的详细日志,显示我可以连接并上传文件。

Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpLogonOpData::Send() in state 0
Status:         Resolving address of my_domain
Status:         Connecting to FTP_server_ip_address:21...
Status:         Connection established, waiting for welcome message...
Trace:          CFtpControlSocket::OnReceive()
Response:   220 (vsFTPd 3.0.3)
Trace:          CFtpLogonOpData::ParseResponse() in state 1
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpLogonOpData::Send() in state 5
Command:    USER user 
Trace:          CFtpControlSocket::OnReceive()
Response:   331 Please specify the password.
Trace:          CFtpLogonOpData::ParseResponse() in state 5
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpLogonOpData::Send() in state 5
Command:    PASS **********
Trace:          CFtpControlSocket::OnReceive()
Response:   230 Login successful.
Trace:          CFtpLogonOpData::ParseResponse() in state 5
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpLogonOpData::Send() in state 6
Command:    SYST
Trace:          CFtpControlSocket::OnReceive()
Response:   215 UNIX Type: L8
Trace:          CFtpLogonOpData::ParseResponse() in state 6
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpLogonOpData::Send() in state 7
Command:    FEAT
Trace:          CFtpControlSocket::OnReceive()
Response:   211-Features:
Trace:          CFtpControlSocket::OnReceive()
Response:    UTF8
Response:    EPRT
Response:    EPSV
Response:    MDTM
Response:    PASV
Response:    REST STREAM
Response:    SIZE
Response:    TVFS
Response:   211 End
Trace:          CFtpLogonOpData::ParseResponse() in state 7
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpLogonOpData::Send() in state 9
Command:    OPTS UTF8 ON
Trace:          CFtpControlSocket::OnReceive()
Response:   200 Always in UTF8 mode.
Trace:          CFtpLogonOpData::ParseResponse() in state 9
Status:         Logged in
Trace:          Measured latency of 35 ms
Trace:          CFtpControlSocket::ResetOperation(0)
Trace:          CControlSocket::ResetOperation(0)
Status:         Retrieving directory listing...
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpListOpData::ListSend() in state 0
Trace:          CFtpChangeDirOpData::Send() in state 0
Trace:          CFtpChangeDirOpData::Send() in state 1
Command:    PWD
Trace:          CFtpControlSocket::OnReceive()
Response:   257 "/home/punc" is the current directory
Trace:          CFtpChangeDirOpData::ParseResponse() in state 1
Trace:          CFtpControlSocket::ResetOperation(0)
Trace:          CControlSocket::ResetOperation(0)
Trace:          CControlSocket::ParseSubcommandResult(0)
Trace:          CFtpListOpData::SubcommandResult() in state 1
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpListOpData::ListSend() in state 2
Trace:          CFtpRawTransferOpData::Send() in state 1
Command:    TYPE I
Trace:          CFtpControlSocket::OnReceive()
Response:   200 Switching to Binary mode.
Trace:          CFtpRawTransferOpData::ParseResponse() in state 1
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpRawTransferOpData::Send() in state 2
Command:    PORT 192,168,1,131,195,121
Trace:          CFtpControlSocket::OnReceive()

Response:   200 PORT command successful. Consider using PASV.
Trace:          CFtpRawTransferOpData::ParseResponse() in state 2
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpRawTransferOpData::Send() in state 4
Command:    LIST
Trace:          CTransferSocket::OnAccept(0)
Trace:          CTransferSocket::OnConnect
Trace:          CTransferSocket::TransferEnd(1)
Trace:          CFtpControlSocket::TransferEnd()
Trace:          CFtpControlSocket::OnReceive()
Response:   150 Here comes the directory listing.
Trace:          CFtpRawTransferOpData::ParseResponse() in state 6
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpRawTransferOpData::Send() in state 7
Trace:          CFtpControlSocket::OnReceive()
Response:   226 Directory send OK.
Trace:          CFtpRawTransferOpData::ParseResponse() in state 7
Trace:          CFtpControlSocket::ResetOperation(0)
Trace:          CControlSocket::ResetOperation(0)
Trace:          CControlSocket::ParseSubcommandResult(0)
Trace:          CFtpListOpData::SubcommandResult() in state 3
Trace:          CFtpControlSocket::ResetOperation(0)
Trace:          CControlSocket::ResetOperation(0)
Status:         Directory listing of "/home/punc" successful
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpLogonOpData::Send() in state 0
Status:         Resolving address of my_domain
Status:         Connecting to FTP_server_ip_address:21...
Status:         Connection established, waiting for welcome message...
Trace:          CFtpControlSocket::OnReceive()
Response:   220 (vsFTPd 3.0.3)
Trace:          CFtpLogonOpData::ParseResponse() in state 1
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpLogonOpData::Send() in state 5
Command:    USER user 
Trace:          CFtpControlSocket::OnReceive()
Response:   331 Please specify the password.
Trace:          CFtpLogonOpData::ParseResponse() in state 5
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpLogonOpData::Send() in state 5
Command:    PASS **********
Trace:          CFtpControlSocket::OnReceive()
Response:   230 Login successful.
Trace:          CFtpLogonOpData::ParseResponse() in state 5
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpLogonOpData::Send() in state 9
Command:    OPTS UTF8 ON
Trace:          CFtpControlSocket::OnReceive()
Response:   200 Always in UTF8 mode.
Trace:          CFtpLogonOpData::ParseResponse() in state 9
Status:         Logged in
Trace:          Measured latency of 50 ms
Trace:          CFtpControlSocket::ResetOperation(0)
Trace:          CControlSocket::ResetOperation(0)
Trace:          CFtpControlSocket::FileTransfer()
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpFileTransferOpData::Send() in state 0
Status:         Starting upload of /Users/user/tiny_dancer/Testing/Platinum Pest Control/API_text_results/Eps 256 Platinum Pest-Pest Control Tulsa.txt
Trace:          CFtpChangeDirOpData::Send() in state 0
Trace:          CFtpChangeDirOpData::Send() in state 2
Command:    CWD /home/punc
Trace:          CFtpControlSocket::OnReceive()
Response:   250 Directory successfully changed.
Trace:          CFtpChangeDirOpData::ParseResponse() in state 2
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpChangeDirOpData::Send() in state 3
Command:    PWD
Trace:          CFtpControlSocket::OnReceive()
Response:   257 "/home/punc" is the current directory
Trace:          CFtpChangeDirOpData::ParseResponse() in state 3
Trace:          CFtpControlSocket::ResetOperation(0)
Trace:          CControlSocket::ResetOperation(0)
Trace:          CControlSocket::ParseSubcommandResult(0)
Trace:          CFtpFileTransferOpData::SubcommandResult() in state 1
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpFileTransferOpData::Send() in state 5
Trace:          CFtpRawTransferOpData::Send() in state 1
Command:    TYPE A
Trace:          CFtpControlSocket::OnReceive()
Response:   200 Switching to ASCII mode.
Trace:          CFtpRawTransferOpData::ParseResponse() in state 1
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpRawTransferOpData::Send() in state 2
Command:    PORT 192,168,1,131,195,122
Trace:          CFtpControlSocket::OnReceive()
Response:   200 PORT command successful. Consider using PASV.
Trace:          CFtpRawTransferOpData::ParseResponse() in state 2
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpRawTransferOpData::Send() in state 4
Command:    STOR Eps 256 Platinum Pest-Pest Control Tulsa.txt
Trace:          CTransferSocket::OnAccept(0)
Trace:          CTransferSocket::OnConnect
Trace:          CTransferSocket::TransferEnd(1)
Trace:          CFtpControlSocket::TransferEnd()
Trace:          CFtpControlSocket::OnReceive()
Response:   150 Ok to send data.
Trace:          CFtpRawTransferOpData::ParseResponse() in state 6
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpRawTransferOpData::Send() in state 7
Trace:          CFtpControlSocket::OnReceive()
Response:   226 Transfer complete.
Trace:          CFtpRawTransferOpData::ParseResponse() in state 7
Trace:          CFtpControlSocket::ResetOperation(0)
Trace:          CControlSocket::ResetOperation(0)
Trace:          CControlSocket::ParseSubcommandResult(0)
Trace:          CFtpFileTransferOpData::SubcommandResult() in state 7
Trace:          CFtpControlSocket::ResetOperation(0)
Trace:          CControlSocket::ResetOperation(0)
Status:         File transfer successful, transferred 8,341 bytes in 1 second
Status:         Retrieving directory listing of "/home/punc"...
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpListOpData::ListSend() in state 0
Trace:          CFtpChangeDirOpData::Send() in state 0
Trace:          CFtpControlSocket::ResetOperation(0)
Trace:          CControlSocket::ResetOperation(0)
Trace:          CControlSocket::ParseSubcommandResult(0)
Trace:          CFtpListOpData::SubcommandResult() in state 1
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpListOpData::ListSend() in state 2
Trace:          CFtpRawTransferOpData::Send() in state 1
Command:    TYPE I
Trace:          CFtpControlSocket::OnReceive()
Response:   200 Switching to Binary mode.
Trace:          CFtpRawTransferOpData::ParseResponse() in state 1
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpRawTransferOpData::Send() in state 2
Command:    PORT 192,168,1,131,195,123
Trace:          CFtpControlSocket::OnReceive()
Response:   200 PORT command successful. Consider using PASV.
Trace:          CFtpRawTransferOpData::ParseResponse() in state 2
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpRawTransferOpData::Send() in state 4
Command:    LIST
Trace:          CTransferSocket::OnAccept(0)
Trace:          CTransferSocket::OnConnect
Trace:          CTransferSocket::TransferEnd(1)
Trace:          CFtpControlSocket::OnReceive()
Response:   150 Here comes the directory listing.
Trace:          CFtpRawTransferOpData::ParseResponse() in state 4
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpRawTransferOpData::Send() in state 5
Trace:          CFtpControlSocket::TransferEnd()
Trace:          CFtpControlSocket::OnReceive()
Response:   226 Directory send OK.
Trace:          CFtpRawTransferOpData::ParseResponse() in state 7
Trace:          CFtpControlSocket::ResetOperation(0)
Trace:          CControlSocket::ResetOperation(0)
Trace:          CControlSocket::ParseSubcommandResult(0)
Trace:          CFtpListOpData::SubcommandResult() in state 3
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpListOpData::ListSend() in state 4
Status:         Calculating timezone offset of server...
Command:    MDTM Eps 256 Platinum Pest-Pest Control Tulsa.txt
Trace:          CFtpControlSocket::OnReceive()
Response:   213 20180120104523
Trace:          CFtpListOpData::ParseResponse() in state 4
Status:         Timezone offset of server is 0 seconds.
Trace:          CFtpControlSocket::ResetOperation(0)
Trace:          CControlSocket::ResetOperation(0)
Status:         Directory listing of "/home/punc" successful

您的 Python 代码正在使用被动模式。

使用 FileZille,您只能在主动模式下连接,而不能在被动模式下连接。

一般应该使用被动模式。由于它不起作用,您必须修复 firewall/NAT 配置。
看我的文章https://winscp.net/eng/docs/ftp_modes


另一种可能是 FTP 服务器在 PASV 响应中报告了错误的 IP 地址。我们无法判断这一点,因为您混淆了日志中的主要 IP 地址。但确实 192.168.1.131 是为专用网络保留的 IP 地址。因此,除非您连接到私有网络内的服务器,否则 IP 地址是错误的。这也包含在之前链接的文章中。

在 vsftpd FTP 服务器中,您使用 pasv_address 指令配置外部 IP 地址。
https://security.appspot.com/vsftpd/vsftpd_conf.html

不太理想的解决方案正在本地解决这个问题:


当然,您也可以在 Python 脚本中使用活动模式。但这与其说是解决方案,不如说是一种变通方法。