You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 02:38:11