最近在和一个第三方的合作中不得已需要使用FTP文件接口。由于FTP Server由对方提供,而且双方背后各自的网络环境都很不单纯等等原因,造成测试环境无法模拟实际情况。测试环境中程序一切正常,但是在部署到生产环境之后发现FTP操作不规律性出现“卡死”现象:程序捕获不到任何异常一直卡着,导致轮巡无法正常工作。
为了解决这个问题,我首先考虑的是对于FTPClient的使用上没有设置超时时间,于是设置了ConnectTimeout、DataTimeout、DefaultTimeout后在生产环境上继续观察,但是问题依旧没有解决。又经过一翻研究之后发现:需要使用被动模式,操作简单描述:
在项目中使用commons-net-3.0.1.jar实现FTP文件的下载,在windows xp上运行正常,但是放到linux上,却出现问题,程序运行到 FTPClient.listFiles()或者FTPClient.retrieveFile()方法时,就停止在那里,什么反应都没有,出现假死状态。google一把,发现很多人也出现了此类问题,最终在一个帖子里找到了解决办法。在调用这两个方法之前,调用FTPClient.enterLocalPassiveMode();这个方法的意思就是每次数据连接之前,ftp client告诉ftp server开通一个端口来传输数据。为什么要这样做呢,因为ftp server可能每次开启不同的端口来传输数据,但是在linux上,由于安全限制,可能某些端口没有开启,所以就出现阻塞。OK,问题解决。
于是我回滚了之前的修改,改为被动模式(关于FTP主动/被动模式的解释,这里我不多说了,关注的朋友可以自己查阅)。但是问题依旧。从FTPClient api本身去解决问题,进行尝试:既设置被动模式又设置超时时间。经过实际测试,发现问题得以解决。下面把我的FTP工具类贴给大家分享,希望能帮到遇到同样问题的人。
import org.apache.commons.net.ftp.FTP; 2 import org.apache.commons.net.ftp.FTPClient; 3 import org.apache.commons.net.ftp.FTPFile; 4 import org.apache.commons.net.ftp.FTPReply; 5 6 import java.io.BufferedInputStream; 7 import java.io.BufferedOutputStream; 8 import java.io.File; 9 import java.io.FileInputStream; 10 import java.io.FileNotFoundException; 11 import java.io.FileOutputStream; 12 import java.io.IOException; 13 import java.io.InputStream; 14 import java.io.OutputStream; 15 import java.net.UnknownHostException; 16 import java.util.ArrayList; 17 import java.util.List; 18 19 public class FtpUtil { 20 public static final String ANONYMOUS_LOGIN = "anonymous"; 21 private FTPClient ftp; 22 private boolean is_connected; 23 24 public FtpUtil() { 25 ftp = new FTPClient(); 26 is_connected = false; 27 } 28 29 public FtpUtil(int defaultTimeoutSecond, int connectTimeoutSecond, int dataTimeoutSecond){ 30 ftp = new FTPClient(); 31 is_connected = false; 32 33 ftp.setDefaultTimeout(defaultTimeoutSecond * 1000); 34 ftp.setConnectTimeout(connectTimeoutSecond * 1000); 35 ftp.setDataTimeout(dataTimeoutSecond * 1000); 36 } 37 38 /** 39 * Connects to FTP server. 40 * 41 * @param host 42 * FTP server address or name 43 * @param port 44 * FTP server port 45 * @param user 46 * user name 47 * @param password 48 * user password 49 * @param isTextMode 50 * text / binary mode switch 51 * @throws IOException 52 * on I/O errors 53 */ 54 public void connect(String host, int port, String user, String password, boolean isTextMode) throws IOException { 55 // Connect to server. 56 try { 57 ftp.connect(host, port); 58 } catch (UnknownHostException ex) { 59 throw new IOException("Can't find FTP server '" + host + "'"); 60 } 61