使用Python ftplib的FTP_TLS调用retrlines()时遭遇EOFError
FTP_TLS调用retrlines下载z/OS PDS成员时的EOFError解决办法
问题根源
你遇到的EOFError大概率是因为FTP_TLS默认只加密控制连接,数据连接(RETR命令用的)还是明文,而z/OS的FTP服务器强制要求数据连接也加密,直接断开连接导致EOF。另外,z/OS的编码、换行符特性在TLS传输下也可能引发异常。
修复方案
1. 强制数据连接加密
FTP_TLS初始化后,控制连接是加密的,但数据连接默认还是明文。你需要调用prot_p()(部分版本中可用set_prot_p(True))来启用数据连接的加密保护,修改后的连接代码:
ftps = FTP_TLS(server, user=user, passwd=password, encoding='ISO8859-1') # 启用所有数据连接的加密模式 ftps.prot_p() login = True
2. 正确处理异常,避免SSL连接紊乱
之前捕获EOFError后引发更多SSL错误,是因为异常发生时SSL连接状态已损坏,继续操作会导致后续握手失败。应该在捕获异常后重置连接:
for member in members: lines = [] try: ftps.retrlines(f'RETR {member}', lines.append) # 后续文件写入逻辑 except EOFError: # 关闭异常连接,重新建立 ftps.close() ftps = FTP_TLS(server, user=user, passwd=password, encoding='ISO8859-1') ftps.prot_p() print(f"成员{member}下载失败,已重置连接") # 可选:重试当前成员 # ftps.retrlines(f'RETR {member}', lines.append)
3. 适配z/OS的编码和换行符
z/OS的PDS成员默认用EBCDIC编码(cp037),你指定的ISO8859-1可能在TLS传输时出现编码转换问题,建议替换编码:
ftps = FTP_TLS(server, user=user, passwd=password, encoding='cp037')
另外,z/OS的换行符是\r,如果后续处理依赖\n,可以自定义回调函数转换:
def process_line(line): lines.append(line.replace('\r', '\n')) ftps.retrlines(f'RETR {member}', process_line)
验证步骤
- 先用FTP命令行工具测试TLS连接:执行
ftp -secure <server>,登录后尝试RETR <member>,看是否能正常下载,排除服务器端配置问题。 - 暂时注释掉
prot_p(),如果同样报错,说明服务器确实强制要求数据连接加密。
内容的提问来源于stack exchange,提问作者Mark Hammack
相关产品推荐
相关产品推荐

