博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[JAVA]Apache FTPClient操作“卡死”问题的分析和解决
阅读量:4636 次
发布时间:2019-06-09

本文共 15918 字,大约阅读时间需要 53 分钟。

    最近在和一个第三方的合作中不得已需要使用FTP文件接口。由于FTP Server由对方提供,而且双方背后各自的网络环境都很不单纯等等原因,造成测试环境无法模拟实际情况。测试环境中程序一切正常,但是在部署到生产环境之后发现FTP操作不规律性出现“卡死”现象:程序捕获不到任何异常一直卡着,导致轮巡无法正常工作(由于担心在轮巡时间间隔内处理不能完成,我没有采用类似quartz或者crontab的定时任务,而是采用while-true然后sleep的方式)。

    为了解决这个问题,我首先考虑的是对于FTPClient的使用上没有设置超时时间,于是设置了ConnectTimeout、DataTimeout、DefaultTimeout后在生产环境上继续观察,但是问题依旧没有解决。后来我有些怀疑FTPClient api本身是不是有什么问题,想实在不行自己实现一个超时机制吧,不过还是不甘心,还是想从FTPClient api本身去解决问题。又经过一翻研究之后发现:需要使用被动模式,以下摘抄别人的一段简单描述:

在项目中使用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主动/被动模式的解释,这里我不多说了,关注的朋友可以自己查阅)。但是问题依旧。于是能想到的就是最有的绝招:实在不行自己实现一个超时机制吧。经过一翻研究最简单的方式就是使用:Future解决:

1 public static void main(String[] args) throws InterruptedException, ExecutionException { 2         final ExecutorService exec = Executors.newFixedThreadPool(1); 3  4         Callable
call = new Callable
() { 5 public String call() throws Exception { 6 Thread.sleep(1000 * 5); 7 return "线程执行完成."; 8 } 9 };10 11 try {12 Future
future = exec.submit(call);13 String obj = future.get(4 * 1000, TimeUnit.MILLISECONDS); // 任务处理超时时间设置14 System.out.println("任务成功返回:" + obj);15 } catch (TimeoutException ex) {16 System.out.println("处理超时啦....");17 ex.printStackTrace();18 } catch (Exception e) {19 System.out.println("处理失败.");20 e.printStackTrace();21 }22 // 关闭线程池23 exec.shutdown();24 25 System.out.println("完毕");26 }

当然了还有很多其他方式:

http://tech.sina.com.cn/s/2008-07-04/1051720260.shtml
http://itindex.net/blog/2010/08/11/1281486125717.html
http://darkmasky.iteye.com/blog/1115047
http://www.cnblogs.com/wasp520/archive/2012/07/06/2580101.html
http://coolxing.iteye.com/blog/1476289
http://www.cnblogs.com/chenying99/archive/2012/10/24/2737924.html

    虽然找到了终极的“必杀技”,但是此时我还是不甘心,还是想从FTPClient api本身去解决问题,但此时看来也别无它他法。只能试试:即设置被动模式又设置超时时间。经过实际测试,发现问题得以解决。下面把我的FTP工具类贴给大家分享,希望能帮到遇到同样问题的人。

1 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  62         // Check rsponse after connection attempt. 63         int reply = ftp.getReplyCode(); 64         if (!FTPReply.isPositiveCompletion(reply)) { 65             disconnect(); 66             throw new IOException("Can't connect to server '" + host + "'"); 67         } 68  69         if (user == "") { 70             user = ANONYMOUS_LOGIN; 71         } 72  73         // Login. 74         if (!ftp.login(user, password)) { 75             is_connected = false; 76             disconnect(); 77             throw new IOException("Can't login to server '" + host + "'"); 78         } else { 79             is_connected = true; 80         } 81  82         // Set data transfer mode. 83         if (isTextMode) { 84             ftp.setFileType(FTP.ASCII_FILE_TYPE); 85         } else { 86             ftp.setFileType(FTP.BINARY_FILE_TYPE); 87         } 88     } 89  90     /** 91      * Uploads the file to the FTP server. 92      *  93      * @param ftpFileName 94      *            server file name (with absolute path) 95      * @param localFile 96      *            local file to upload 97      * @throws IOException 98      *             on I/O errors 99      */100     public void upload(String ftpFileName, File localFile) throws IOException {101         // File check.102         if (!localFile.exists()) {103             throw new IOException("Can't upload '" + localFile.getAbsolutePath() + "'. This file doesn't exist.");104         }105 106         // Upload.107         InputStream in = null;108         try {109 110             // Use passive mode to pass firewalls.111             ftp.enterLocalPassiveMode();112 113             in = new BufferedInputStream(new FileInputStream(localFile));114             if (!ftp.storeFile(ftpFileName, in)) {115                 throw new IOException("Can't upload file '" + ftpFileName + "' to FTP server. Check FTP permissions and path.");116             }117 118         } finally {119             try {120                 in.close();121             } catch (IOException ex) {122             }123         }124     }125 126     /**127      * Downloads the file from the FTP server.128      * 129      * @param ftpFileName130      *            server file name (with absolute path)131      * @param localFile132      *            local file to download into133      * @throws IOException134      *             on I/O errors135      */136     public void download(String ftpFileName, File localFile) throws IOException {137         // Download.138         OutputStream out = null;139         try {140             // Use passive mode to pass firewalls.141             ftp.enterLocalPassiveMode();142 143             // Get file info.144             FTPFile[] fileInfoArray = ftp.listFiles(ftpFileName);145             if (fileInfoArray == null) {146                 throw new FileNotFoundException("File " + ftpFileName + " was not found on FTP server.");147             }148 149             // Check file size.150             FTPFile fileInfo = fileInfoArray[0];151             long size = fileInfo.getSize();152             if (size > Integer.MAX_VALUE) {153                 throw new IOException("File " + ftpFileName + " is too large.");154             }155 156             // Download file.157             out = new BufferedOutputStream(new FileOutputStream(localFile));158             if (!ftp.retrieveFile(ftpFileName, out)) {159                 throw new IOException("Error loading file " + ftpFileName + " from FTP server. Check FTP permissions and path.");160             }161 162             out.flush();163         } finally {164             if (out != null) {165                 try {166                     out.close();167                 } catch (IOException ex) {168                 }169             }170         }171     }172 173     /**174      * Removes the file from the FTP server.175      * 176      * @param ftpFileName177      *            server file name (with absolute path)178      * @throws IOException179      *             on I/O errors180      */181     public void remove(String ftpFileName) throws IOException {182         if (!ftp.deleteFile(ftpFileName)) {183             throw new IOException("Can't remove file '" + ftpFileName + "' from FTP server.");184         }185     }186 187     /**188      * Lists the files in the given FTP directory.189      * 190      * @param filePath191      *            absolute path on the server192      * @return files relative names list193      * @throws IOException194      *             on I/O errors195      */196     public List
list(String filePath) throws IOException {197 List
fileList = new ArrayList
();198 199 // Use passive mode to pass firewalls.200 ftp.enterLocalPassiveMode();201 202 FTPFile[] ftpFiles = ftp.listFiles(filePath);203 int size = (ftpFiles == null) ? 0 : ftpFiles.length;204 for (int i = 0; i < size; i++) {205 FTPFile ftpFile = ftpFiles[i];206 if (ftpFile.isFile()) {207 fileList.add(ftpFile.getName());208 }209 }210 211 return fileList;212 }213 214 /**215 * Sends an FTP Server site specific command216 * 217 * @param args218 * site command arguments219 * @throws IOException220 * on I/O errors221 */222 public void sendSiteCommand(String args) throws IOException {223 if (ftp.isConnected()) {224 try {225 ftp.sendSiteCommand(args);226 } catch (IOException ex) {227 }228 }229 }230 231 /**232 * Disconnects from the FTP server233 * 234 * @throws IOException235 * on I/O errors236 */237 public void disconnect() throws IOException {238 239 if (ftp.isConnected()) {240 try {241 ftp.logout();242 ftp.disconnect();243 is_connected = false;244 } catch (IOException ex) {245 }246 }247 }248 249 /**250 * Makes the full name of the file on the FTP server by joining its path and251 * the local file name.252 * 253 * @param ftpPath254 * file path on the server255 * @param localFile256 * local file257 * @return full name of the file on the FTP server258 */259 public String makeFTPFileName(String ftpPath, File localFile) {260 if (ftpPath == "") {261 return localFile.getName();262 } else {263 String path = ftpPath.trim();264 if (path.charAt(path.length() - 1) != '/') {265 path = path + "/";266 }267 268 return path + localFile.getName();269 }270 }271 272 /**273 * Test coonection to ftp server274 * 275 * @return true, if connected276 */277 public boolean isConnected() {278 return is_connected;279 }280 281 /**282 * Get current directory on ftp server283 * 284 * @return current directory285 */286 public String getWorkingDirectory() {287 if (!is_connected) {288 return "";289 }290 291 try {292 return ftp.printWorkingDirectory();293 } catch (IOException e) {294 }295 296 return "";297 }298 299 /**300 * Set working directory on ftp server301 * 302 * @param dir303 * new working directory304 * @return true, if working directory changed305 */306 public boolean setWorkingDirectory(String dir) {307 if (!is_connected) {308 return false;309 }310 311 try {312 return ftp.changeWorkingDirectory(dir);313 } catch (IOException e) {314 }315 316 return false;317 }318 319 /**320 * Change working directory on ftp server to parent directory321 * 322 * @return true, if working directory changed323 */324 public boolean setParentDirectory() {325 if (!is_connected) {326 return false;327 }328 329 try {330 return ftp.changeToParentDirectory();331 } catch (IOException e) {332 }333 334 return false;335 }336 337 /**338 * Get parent directory name on ftp server339 * 340 * @return parent directory341 */342 public String getParentDirectory() {343 if (!is_connected) {344 return "";345 }346 347 String w = getWorkingDirectory();348 setParentDirectory();349 String p = getWorkingDirectory();350 setWorkingDirectory(w);351 352 return p;353 }354 355 /**356 * Get directory contents on ftp server357 * 358 * @param filePath359 * directory360 * @return list of FTPFileInfo structures361 * @throws IOException362 */363 public List
listFiles(String filePath) throws IOException {364 List
fileList = new ArrayList
();365 366 // Use passive mode to pass firewalls.367 ftp.enterLocalPassiveMode();368 FTPFile[] ftpFiles = ftp.listFiles(filePath);369 int size = (ftpFiles == null) ? 0 : ftpFiles.length;370 for (int i = 0; i < size; i++) {371 FTPFile ftpFile = ftpFiles[i];372 FfpFileInfo fi = new FfpFileInfo();373 fi.setName(ftpFile.getName());374 fi.setSize(ftpFile.getSize());375 fi.setTimestamp(ftpFile.getTimestamp());376 fi.setType(ftpFile.isDirectory());377 fileList.add(fi);378 }379 380 return fileList;381 }382 383 /**384 * Get file from ftp server into given output stream385 * 386 * @param ftpFileName387 * file name on ftp server388 * @param out389 * OutputStream390 * @throws IOException391 */392 public void getFile(String ftpFileName, OutputStream out) throws IOException {393 try {394 // Use passive mode to pass firewalls.395 ftp.enterLocalPassiveMode();396 397 // Get file info.398 FTPFile[] fileInfoArray = ftp.listFiles(ftpFileName);399 if (fileInfoArray == null) {400 throw new FileNotFoundException("File '" + ftpFileName + "' was not found on FTP server.");401 }402 403 // Check file size.404 FTPFile fileInfo = fileInfoArray[0];405 long size = fileInfo.getSize();406 if (size > Integer.MAX_VALUE) {407 throw new IOException("File '" + ftpFileName + "' is too large.");408 }409 410 // Download file.411 if (!ftp.retrieveFile(ftpFileName, out)) {412 throw new IOException("Error loading file '" + ftpFileName + "' from FTP server. Check FTP permissions and path.");413 }414 415 out.flush();416 417 } finally {418 if (out != null) {419 try {420 out.close();421 } catch (IOException ex) {422 }423 }424 }425 }426 427 /**428 * Put file on ftp server from given input stream429 * 430 * @param ftpFileName431 * file name on ftp server432 * @param in433 * InputStream434 * @throws IOException435 */436 public void putFile(String ftpFileName, InputStream in) throws IOException {437 try {438 // Use passive mode to pass firewalls.439 ftp.enterLocalPassiveMode();440 441 if (!ftp.storeFile(ftpFileName, in)) {442 throw new IOException("Can't upload file '" + ftpFileName + "' to FTP server. Check FTP permissions and path.");443 }444 } finally {445 try {446 in.close();447 } catch (IOException ex) {448 }449 }450 }451 }

 

转载于:https://www.cnblogs.com/CopyPaster/p/3494579.html

你可能感兴趣的文章
[NOI2005]聪聪与可可(期望dp)
查看>>
POJ 3723
查看>>
Maven的安装
查看>>
angular初步认识一
查看>>
springmvc3.2+spring+hibernate4全注解方式整合(一)
查看>>
Elgg网站迁移指南
查看>>
素数筛法优化
查看>>
installshield 注册dll
查看>>
Sublime Text 3 及Package Control 安装(附上一个3103可用的Key)
查看>>
LTE QCI分类 QoS
查看>>
Get MAC address using POSIX APIs
查看>>
bzoj2120
查看>>
基于uFUN开发板的心率计(一)DMA方式获取传感器数据
查看>>
【dp】船
查看>>
oracle, group by, having, where
查看>>
⑥python模块初识、pyc和PyCodeObject
查看>>
object-c中管理文件和目录:NSFileManager使用方法
查看>>
Kibana:分析及可视化日志文件
查看>>
nodejs pm2使用
查看>>
cocos2d-x 3.10 PageView BUG
查看>>