Python ftplib实现FTPS传输失败,WinSCP却可正常运行
FTPS文件传输426错误问题排查与解决建议
问题概述
使用Python的ftplib实现FTPS文件传输时,第一个文件已在服务器生成且内容正确,但最终抛出ftplib.error_temp: 426 Transfer failed异常,无法完成传输。WinSCP可正常连接并传输文件,寻求可行的Python解决方案。
代码片段
# 注:代码存在导入缺失、方法调用错误及未定义变量问题 import pysftp from io import BytesIO # 补充缺失的导入 from ftplib import FTP_TLS # 补充缺失的导入 user = "..." password = "..." host = "..." port = 21 targetdir = "ftp_test_a" # 补充缺失的目标目录定义 class FtpDirectory: def __init__(self): self.ftp = None def __enter__(self): self.ftp = FTP_TLS() self.ftp.debugging = 1 self.ftp.connect(host, port) self.ftp.login(user, password) # ftplib.FTP_TLS无prot_p()方法,替换为发送PROT命令 self.ftp.sendcmd('PROT P') self.ftp.cwd(targetdir) return self.ftp files = [('test1.txt', b'test1content'), ('test2.txt', b'test2content')] with FtpDirectory() as ftp: for file in files: ftp.storbinary("STOR " + file[0], BytesIO(file[1]))
错误日志
*resp* '220 myexampleserver.xyz X2 WS_FTP Server 8.7.2(01051325)' *cmd* 'AUTH TLS' *resp* '234 SSL enabled and waiting for negotiation' *cmd* 'USER myexampleuser' *resp* '331 Enter password' *cmd* 'PASS ************' *resp* '230 User logged in' *cmd* 'PBSZ 0' *resp* '200 PBSZ=0' *cmd* 'PROT P' *resp* '200 PRIVATE data channel protection level set' *cmd* 'CWD ftp_test_a' *resp* '250 Command CWD succeed' *cmd* 'TYPE I' *resp* '200 Transfer mode set to BINARY' *cmd* 'PASV' *resp* '227 Entering Passive Mode (111,222,33,44,156,110).' *cmd* 'STOR test.txt' *resp* '150 Uploading in BINARY file test1.txt' <---- 耗时较久,文件已出现在服务器 *cmd* 'QUIT' *resp* '426 Transfer failed'
WinSCP配置对比
- 加密方式:要求显式TLS/SSL(对应代码中
AUTH TLS流程) - 传输模式:被动模式(与代码中
PASV命令一致) - 数据通道保护:私有模式(对应
PROT P命令)
环境信息
Python环境支持TLS 1.3(通过urlopen('https://www.howsmyssl.com/a/check', context=ssl._create_unverified_context()).read()验证)
解决建议
1. 修正现有代码错误
- 补充缺失的导入语句:
from ftplib import FTP_TLS和from io import BytesIO - 替换无效的
prot_p()方法调用:使用self.ftp.sendcmd('PROT P')发送数据通道保护命令 - 定义
targetdir变量,明确目标目录路径
2. 处理数据通道TLS会话复用问题
WS_FTP Server 8.7.2可能要求数据通道复用控制通道的TLS会话,而ftplib默认未处理该逻辑。可尝试在每次传输前重新初始化数据通道:
with FtpDirectory() as ftp: for file in files: # 重新设置数据通道加密 ftp.sendcmd('PROT P') ftp.storbinary("STOR " + file[0], BytesIO(file[1]))
3. 使用pysftp替代ftplib
pysftp基于paramiko,对FTPS的兼容性更完善,示例代码:
import pysftp from io import BytesIO user = "..." password = "..." host = "..." port = 21 targetdir = "ftp_test_a" files = [('test1.txt', b'test1content'), ('test2.txt', b'test2content')] # 若服务器证书未被信任,添加cnopts=pysftp.CnOpts(hostkeys=None)(仅测试环境使用) with pysftp.Connection(host, username=user, password=password, port=port) as sftp: sftp.cwd(targetdir) for file_name, content in files: with sftp.open(file_name, 'wb') as f: f.write(content)
4. 检查服务器端日志
查看WS_FTP Server的详细日志,确认426错误的具体触发原因(如数据连接超时、TLS握手失败、权限限制等),针对性调整配置。
内容的提问来源于stack exchange,提问作者A. L
相关产品推荐
相关产品推荐

