如何在Python ftplib主动模式下指定外部IP地址?
解决Python FTP主动模式下指定外部IP的问题
在FTP主动模式下,服务器需要主动发起与客户端数据端口的连接。如果你的机器处于NAT网络后,服务器只能拿到你的内网IP,无法建立数据连接,这就是你执行ftp.dir()时超时的原因——WinSCP/FileZilla里的“外部IP”设置就是用来告诉服务器你的公网IP,让它能正确连接到你。
Python标准库的ftplib没有直接提供设置外部IP的接口,但可以通过扩展FTP类来实现:
自定义FTP类指定外部IP
from ftplib import FTP import socket class FTPWithExternalIP(FTP): def __init__(self, external_ip, *args, **kwargs): self.external_ip = external_ip super().__init__(*args, **kwargs) def makeport(self): # 创建数据套接字,绑定本地任意可用端口 data_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) data_sock.bind(('', 0)) data_sock.listen(1) # 提取本地端口并转换为FTP协议要求的格式 local_port = data_sock.getsockname()[1] ip_segments = list(map(int, self.external_ip.split('.'))) port_segments = [local_port >> 8 & 0xff, local_port & 0xff] ftp_port_str = ','.join(map(str, ip_segments + port_segments)) # 向服务器发送PORT命令,告知公网IP和数据端口 self.sendport(ftp_port_str) return data_sock
使用方式
把你的公网IP传入自定义类,按正常流程初始化、连接、登录即可:
# 替换成你的实际信息 EXTERNAL_IP = "123.123.123.123" FTP_SERVER = "ftp.example.com" USERNAME = "your_username" PASSWORD = "your_password" ftp = FTPWithExternalIP(EXTERNAL_IP) ftp.connect(FTP_SERVER, 21) ftp.login(USERNAME, PASSWORD) ftp.setpasv(False) # 启用主动模式 # 现在可以正常执行目录操作 ftp.dir() ftp.quit()
关键注意事项
- 确认你的公网IP正确:可以通过公网IP查询工具获取
- 防火墙配置:确保本地防火墙允许FTP数据连接入站(主动模式下服务器会连接你随机的高位端口,若要固定端口,可修改
bind(('', 0))为bind(('', 固定端口)),同时在NAT设备上配置端口转发) - NAT端口转发:如果你的机器在路由器后,需要在路由器上把FTP数据端口(或指定的固定端口)转发到你的内网IP
你之前尝试的ftp.connect指定源地址,只是绑定本地网卡的IP,并没有把公网IP告知服务器;而忽略返回IP的方案通常针对被动模式,主动模式下不适用。
内容的提问来源于stack exchange,提问作者Naveen Kumar
相关产品推荐
相关产品推荐

