PLC通过Python发送文件至FTP服务器时出现451错误的排查求助
使用PLC通过Python代码向FTP服务器发送文件时,文件看似传输成功,但返回错误 FTP 451 Error closing file.--[5370]--。
环境
网络中的PLC向另一系统上的FTP服务器传输文件。
PLC命令行FTP操作响应
ftp> Send C:\blabla
200 PORT command successful.
150 Opening ASCII mode data connection. (192,168,1,100,58508)
451 Error closing file.--[5370]--
ftp: 11738 bytes sent in 0.00Seconds 5869.00Kbytes/sec.
运行在PLC上的Python代码
def upload_file(ftp_server, ftp_user, ftp_password, file_path, remote_path): try: ftp = ftplib.FTP(ftp_server) ftp.login(user=ftp_user, passwd=ftp_password) with open(file_path, 'rb') as file: ftp.cwd(remote_path) filename = os.path.basename(file_path) ftp.storbinary(f'STOR {filename}', file) print(f"Successfully uploaded {filename} to {remote_path} on {ftp_server}.") ftp.quit() return True, "" except ftplib.all_errors as e: print(f"FTP error: {e}") return False, f"FTP error: {e}" ftp_server = '' ftp_user = '' ftp_password = '' plc = pyads.Connection('127.0.0.1.1.1', pyads.PORT_TC3PLC1) plc.open() running = True while(running): Send_file = plc.read_by_name('PLC variable', pyads.PLCTYPE_BOOL) if Send_file: source_path = plc.read_by_name('PLC variable', pyads.PLCTYPE_STRING) destination_path = plc.read_by_name('PLC variable', pyads.PLCTYPE_STRING) is_successful, error_message = upload_file(ftp_server, ftp_user, ftp_password, source_path, destination_path) plc.write_by_name('PLC variable', is_successful) if is_successful: print("File transfer completed successfully.") else: print("File transfer failed.") plc.write_by_name('PLC variable', error_message) plc.write_by_name('PLC variable', True) plc.close()
代码写入目标系统其他目录正常,但写入某特定目录时触发上述错误,网上未找到该具体错误的相关信息,求修复或排查方法。
检查目标目录权限
该错误大概率是FTP服务器对特定目录的权限限制导致:确认FTP用户对该目录拥有写入、修改、删除权限,同时排查目录是否被其他进程锁定,或存在ACL访问控制列表的特殊限制。验证目录空间与文件属性
检查目标目录所在磁盘是否已满,或文件系统是否设置了用户配额;同时确认上传文件名是否包含服务器禁止的特殊字符,以及目标目录中是否存在同名且被占用的文件。调整FTP传输模式
命令行使用ASCII模式传输,而Python代码用storbinary二进制模式,尝试切换模式测试:- 若上传文本文件,改用
storlines方法; - 或在代码中显式设置ASCII模式:
ftp.set_ascii()后再执行传输,对比结果。
- 若上传文本文件,改用
捕获更详细的错误信息
修改Python代码,在storbinary调用后增加ftp.getresp()获取服务器完整响应,或在异常捕获中打印更多FTP会话细节,帮助定位问题。查看FTP服务器端日志
登录FTP服务器,查看系统日志或FTP服务日志(如Windows事件查看器、Linux的/var/log/vsftpd.log等),错误码[5370]是服务器内部错误码,日志中会有具体原因说明(如文件系统错误、权限验证失败等)。优化FTP会话管理
当前代码中ftp.quit()放在with块外,若传输过程中出现异常可能导致会话未正常关闭。调整代码结构,确保会话无论成功失败都能正确关闭:def upload_file(ftp_server, ftp_user, ftp_password, file_path, remote_path): ftp = None try: ftp = ftplib.FTP(ftp_server) ftp.login(user=ftp_user, passwd=ftp_password) with open(file_path, 'rb') as file: ftp.cwd(remote_path) filename = os.path.basename(file_path) ftp.storbinary(f'STOR {filename}', file) print(f"Successfully uploaded {filename} to {remote_path} on {ftp_server}.") return True, "" except ftplib.all_errors as e: print(f"FTP error: {e}") return False, f"FTP error: {e}" finally: if ftp is not None: try: ftp.quit() except: ftp.close()
内容的提问来源于stack exchange,提问作者user24564605

