这两天一直在为一个FTP上传文件的项目纠结
以前的员工用sun.net.ftp.FtpClient写了一个上传文件项目,经常出现小问题,公司要求优化,并将
sun.net.ftp.FtpClient 改成apache的FtpClient
代码修改以后apache FtpClient 能够登陆,
ftp.login(user, pass) 成功
但是其它操作ftp.listNames(),storeFile 一执行就报错
java.net.SocketException: Connection reset
开始我以为是 主被动模式问题
当前用的jdk1.6版本 这个版本的sun.net.ftp.FtpClient只有被动模式
我确认我的代码中有加入 ftp.enterLocalActiveMode();
我尝试换成主动模式试了,肯定还是不行,服务器根本不会主动连接我的ftp客户端
(对方服务器配置的就是被动模式)
再次分析问题,
1.sun.net.ftp.FtpClient可以连接并上传文件
2.apache的FtpClient 可以login成功
3.异常报错指向apache的FtpClient PASV()这个方法
4.我尝试直接使用ftp协议pasv 立刻就提示 java.net.SocketException: Connection reset
难道sun.net.ftp.FtpClient没有运行PASV指令 ?
于是我查看了sun.net.ftp.FtpClient源码,果然其中有一段
if (issueCommand("EPSV ALL") == FTP_SUCCESS) { if (issueCommand("EPSV") == FTP_ERROR){ .... } else { if (issueCommand("PASV") == FTP_ERROR)
它先执行的是EPSV ALL
回过头来查询apacheClient 源码
boolean attemptEPSV = (isUseEPSVwithIPv4()) || (isInet6Address); if ((attemptEPSV) && (epsv() == 229)) { __parseExtendedPassiveModeReply((String)this._replyLines.get(0)); } else { if (isInet6Address) { return null; } if (pasv() != 227) { return null; }
原来如此
修改代码加上ftp.setUseEPSVwithIPv4(true);
终于文件上传成功了.
注意 我用的是 commons-net-3.0.jar
为什么PASV不能执行,继续找ing....