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

为何FTP服务器可检索文件名却无法获取文件对象?

问题描述

使用Apache Commons Net库访问专用硬件搭载的嵌入式FTP服务器时出现异常:listNames()方法可正常返回结果,但listFiles()方法无法获取有效文件对象。
硬件官方文档仅明确要求FTP连接必须使用主动模式,测试环境为无公网接入的本地WiFi网络,测试代码运行在Android应用中。

测试代码

ftpClient.connect(FTP_IP, 21);
Log.e(TAG, "reply string after connect():" + ftpClient.getReplyString());
ftpClient.enterLocalActiveMode();
ftpClient.enterRemoteActiveMode(InetAddress.getByName(FTP_IP), 21);
ftpClient.login(FTP_USERNAME, FTP_PASSWORD);
Log.e(TAG, "reply string after login(): " + ftpClient.getReplyString());

ftpClient.sendCommand(FTPCmd.LIST);
Log.e(TAG, "reply string for LIST: " + ftpClient.getReplyString());

ftpClient.sendCommand(FTPCmd.NAME_LIST);
Log.e(TAG, "reply string for NLST: " + ftpClient.getReplyString());

remoteFiles = ftpClient.listFiles();
Log.e(TAG, "number of remote FTPFile objects returned: " + remoteFiles.length);

remoteFileNames = ftpClient.listNames();
Log.e(TAG, "remote file names returned: " + remoteFileNames);

运行日志

2022-06-29 17:07:02.853 21263-22717/spinner.fakdown E/FTP: reply string after connect():220--- Welcome to *** FTP
    220---   By *** ---
    220 --   Version: 1.0 FTP-2015-04-08 - modify *** 2016-09-14 ver2   --
2022-06-29 17:07:02.875 21263-22717/spinner.f E/FTP: reply string after login(): 230 OK.
2022-06-29 17:07:02.881 21263-22717/spinner.f E/FTP: reply string for LIST: 425 No data connection
2022-06-29 17:07:02.888 21263-22717/spinner.f E/FTP: reply string for NLST: 425 No data connection
2022-06-29 17:07:03.235 21263-22717/spinner.f E/FTP: number of remote FTPFile objects returned: 0
2022-06-29 17:07:03.485 21263-22717/spinner.f E/FTP: remote file names returned: 6

从返回的425错误码初步判断问题和FTP主被动模式配置相关,但多次调整配置未解决。

已完成验证项

  • Android端Turbo Client应用可正常访问该FTP服务器、浏览全部文件
  • 已尝试所有可用的FTPClientConfig配置参数(如FTPClientConfig.SYST_UNIX),均未解决问题

解决方案

核心问题出在主动模式配置错误,以及Android环境下的主动模式适配问题,按以下步骤调整即可:

  • 删除冗余错误的主动模式配置
    代码中同时调用enterLocalActiveMode()和enterRemoteActiveMode(InetAddress.getByName(FTP_IP), 21)是完全错误的。FTP主动模式下仅需调用enterLocalActiveMode()即可,enterRemoteActiveMode属于非标准API,作用是要求服务器端进入主动连接模式,传入21端口(FTP控制通道默认端口)作为数据连接端口,会直接导致数据链路建立失败,触发425错误。
  • 修复Android环境下主动模式的IP上报问题
    Apache Commons Net在主动模式下会默认自动探测本机IP并通过PORT命令上报给服务器,但Android设备存在多网卡(蜂窝网卡、虚拟网卡、WiFi网卡),自动探测经常会拿到非当前WiFi局域网的IP地址,导致服务器无法回连客户端开放的数据端口,报425错误。需要在开启主动模式后手动指定上报的IP地址:
    ftpClient.enterLocalActiveMode();
    // 自行实现getLocalWifiIpAddress()方法,获取当前设备连接WiFi后分配到的局域网IPv4地址
    ftpClient.setActiveExternalIPAddress(getLocalWifiIpAddress());
    // 可选:固定主动模式数据端口范围,避免系统随机分配的高端口被Android系统防火墙拦截
    ftpClient.setActivePortRange(50000, 51000);
    
  • 移除手动发送原始FTP命令的测试代码
    在调用封装方法前手动发送FTPCmd.LIST和FTPCmd.NAME_LIST原始命令,会提前触发服务器的数据连接尝试,打乱控制通道的状态机,导致后续封装方法调用时链路状态异常。这部分测试代码需要全部删除,不要在业务逻辑里混用原始命令和封装好的API。
  • 开启宽松解析适配嵌入式FTP的非标准列表格式
    这类老旧定制化嵌入式FTP服务器的LIST命令返回格式大多不完全符合标准SYST规范,不需要反复切换FTPClientConfig的系统类型参数,直接开启宽松解析即可:
    FTPClientConfig config = new FTPClientConfig();
    config.setLenientFutureDates(true);
    ftpClient.configure(config);
    
  • 确认Android权限配置
    主动模式下客户端需要开放本地端口监听服务器的回连请求,确保应用已经在AndroidManifest中声明android.permission.INTERNET权限,且没有被系统安全规则、防火墙限制端口监听权限。

日志里手动发送NLST命令返回425,但后续listNames()能正常返回6个文件名,本质是第一次手动发命令时数据链路建立失败,listNames()方法内部重置了控制通道状态重新发起请求才执行成功;而listFiles()依赖LIST命令返回的完整文件属性数据,对链路稳定性、格式兼容性要求更高,配置存在问题时会直接返回空数组。


内容的提问来源于stack exchange,提问作者Spinner

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 19:06:34