FTP连接池
我们项目使用的是 Apache的(commons-net-3.2.jar) FTPClient,但是系统偶尔会有异常,趁着刚解决完,总结一下。
日志中提示是类似
java.lang.Exception: FTP response 421 received. Server closed connection.
上网上一查,说是FTP服务端连接数已满了,出现这种问题一般是,部分连接占用的时间太久,导致新连接获取不到,从而抛出的异常,找到问题就方便下手了(^_^);
我的思路是,既然连接会出问题,那就从这里入手,
- 使用FTP连接池,管理连接
- 初始化连接池,设置超时时间,
- 连接数满时,等待连接释放
我的连接池这一块采用的也是Apache的(commons-pool2-2.2.jar)GenericObjectPool,大概有一下几个类
- 配置类
package com.i1stcs.mvs.utils.ftp; //FTPClient配置类 class FTPConfig { private String host; private int port; private String username; private String password; private String encoding; private String workPath; private int maxTotal; private int maxWaitMillis; public String getHost() { return host; } public void setHost(String host) { this.host = host; } public int getPort() { return port; } public void setPort(int port) { this.port = port; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getEncoding() { return encoding; } public void setEncoding(String encoding) { this.encoding = encoding; } public String getWorkPath() { return workPath; } public void setWorkPath(String workPath) { this.workPath = workPath; } public int getMaxTotal() { return maxTotal; } public void setMaxTotal(int maxTotal) { this.maxTotal = maxTotal; } public int getMaxWaitMillis() { return maxWaitMillis; } public void setMaxWaitMillis(int maxWaitMillis) { this.maxWaitMillis = maxWaitMillis; } } - 连接池实现类
package com.i1stcs.mvs.utils.ftp; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.pool2.impl.GenericObjectPool; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.i1stcs.mvs.utils.PropertiesUtil; public class FTPPool { private static final GenericObjectPool<FTPClient> internalPool; private static Logger logger = LoggerFactory.getLogger(FTPPool.class); static { String ip = PropertiesUtil.getValue("ftp.server.ip", ""); String userName = PropertiesUtil.getValue("ftp.server.username", ""); String password = PropertiesUtil.getValue("ftp.server.password", ""); String encoding = PropertiesUtil.getValue("ftp.server.encoding", "UTF-8"); int port = PropertiesUtil.getValue("ftp.server.port", 21); int maxTotal = PropertiesUtil.getValue("ftp.server.maxTotal", 8); int maxWaitMillis = PropertiesUtil.getValue("ftp.server.maxWaitMillis", 30_000); FTPConfig config = new FTPConfig(); config.setEncoding(encoding); config.setHost(ip); config.setUsername(userName); config.setPassword(password); config.setPort(port); config.setMaxTotal(maxTotal); config.setMaxWaitMillis(maxWaitMillis); GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); poolConfig.setMaxTotal(config.getMaxTotal());// 不设置的话默认是8 poolConfig.setMaxWaitMillis(config.getMaxWaitMillis());// 不设置默认无限等待 internalPool = new GenericObjectPool<FTPClient>(new FTPPoolFactory(config), poolConfig); } /** * 获取资源 * * @return */ public static FTPClient getFTPClient() { try { return internalPool.borrowObject(); } catch (Exception e) { logger.error("获取FTP连接异常:", e); return null; } } /** * 归还资源 * * @param ftpClient */ public static void returnFTPClient(FTPClient ftpClient) { try { internalPool.returnObject(ftpClient); } catch (Exception e) { logger.error("释放FTP连接异常:", e); } } /** * 销毁池子 */ public static void destroy() { try { internalPool.close(); } catch (Exception e) { logger.error("销毁FTP数据源异常:", e); } } } - 连接池工厂类
package com.i1stcs.mvs.utils.ftp; import java.io.IOException; import java.net.SocketException; import org.apache.commons.net.ftp.FTP; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPClientConfig; import org.apache.commons.net.ftp.FTPReply; import org.apache.commons.pool2.PooledObject; import org.apache.commons.pool2.PooledObjectFactory; import org.apache.commons.pool2.impl.DefaultPooledObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; class FTPPoolFactory implements PooledObjectFactory<FTPClient> { private static Logger logger = LoggerFactory.getLogger(FTPPoolFactory.class); private FTPConfig ftpConfig; private static int BUFF_SIZE = 256000; public FTPPoolFactory(FTPConfig ftpConfig) { this.ftpConfig = ftpConfig; } @Override public PooledObject<FTPClient> makeObject() throws Exception { FTPClient ftpClient = new FTPClient(); ftpClient.setDefaultPort(ftpConfig.getPort()); ftpClient.setConnectTimeout(30000); ftpClient.setDataTimeout(180000); ftpClient.setControlKeepAliveTimeout(60); ftpClient.setControlKeepAliveReplyTimeout(60); ftpClient.setControlEncoding(ftpConfig.getEncoding()); FTPClientConfig clientConfig = new FTPClientConfig(FTPClientConfig.SYST_UNIX); clientConfig.setServerLanguageCode(ftpConfig.getEncoding()); ftpClient.configure(clientConfig); try { ftpClient.connect(ftpConfig.getHost()); } catch (SocketException exp) { logger.warn("connect timeout with FTP server:" + ftpConfig.getHost()); throw new Exception(exp.getMessage()); } catch (IOException exp) { logger.warn("connect FTP server:" + ftpConfig.getHost() + " meet error:" + exp.getMessage()); throw new Exception(exp.getMessage()); } int reply = ftpClient.getReplyCode(); if (!FTPReply.isPositiveCompletion(reply)) { ftpClient.disconnect(); logger.error("FTPServer refused connection"); return null; } boolean result = ftpClient.login(ftpConfig.getUsername(), ftpConfig.getPassword()); if (!result) { logger.warn("FTP server refused refused connection."); throw new Exception( "login failed with FTP server:" + ftpConfig.getHost() + " may user name and password is wrong"); } ftpClient.setBufferSize(BUFF_SIZE); ftpClient.setFileType(FTP.BINARY_FILE_TYPE); ftpClient.setFileTransferMode(FTP.COMPRESSED_TRANSFER_MODE); ftpClient.changeWorkingDirectory(ftpConfig.getWorkPath()); return new DefaultPooledObject<FTPClient>(ftpClient); } @Override public void destroyObject(PooledObject<FTPClient> pooledObject) throws Exception { FTPClient ftpClient = pooledObject.getObject(); try { ftpClient.logout(); if (ftpClient.isConnected()) { ftpClient.disconnect(); } } catch (IOException e) { throw new RuntimeException("Could not disconnect from server.", e); } } @Override public boolean validateObject(PooledObject<FTPClient> pooledObject) { FTPClient ftpClient = pooledObject.getObject(); try { return ftpClient.sendNoOp();// } catch (IOException e) { logger.error("Failed to validate client:", e); return false; } } @Override public void activateObject(PooledObject<FTPClient> p) throws Exception { // TODO Auto-generated method stub } @Override public void passivateObject(PooledObject<FTPClient> p) throws Exception { // TODO Auto-generated method stub } } - FTP工具类
package com.songyz.ftp; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPFile; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.i1stcs.mvs.utils.PropertiesUtil; public class FTPHelper { private static final Logger log = LoggerFactory.getLogger(FTPHelper.class); public static FTPCommand createDelDirCmd(String remotePath) { return new DeleteDirCommand(remotePath); } public static FTPCommand createDelFileCmd(String remoteFile) { return new DeleteFileCommand(remoteFile); } public static void execute(FTPCommand... cmds) throws Exception { FTPClient client = null; try { client = FTPPool.getFTPClient(); String mode = PropertiesUtil.getValue("ftp.server.mode", "localactive"); String workpath = PropertiesUtil.getValue("ftp.server.workpath", "./"); for (FTPCommand cmd : cmds) { client.changeWorkingDirectory(workpath); if (mode.equals("localactive")) client.enterLocalActiveMode(); else if (mode.equals("localpassive")) client.enterLocalPassiveMode(); else client.enterRemotePassiveMode(); cmd.isOK = cmd.doAction(client); if (cmd.isOK == false) { if (cmd.error == null || cmd.error.isEmpty()) { String clsName = cmd.getClass().getName(); cmd.error = "execute command:" + clsName.substring(clsName.lastIndexOf("$") + 1) + " failed -- " + client.getReplyString(); } throw new Exception(cmd.error); } } } finally { FTPPool.returnFTPClient(client); } } public static abstract class FTPCommand { protected boolean isOK = false; protected String error = ""; public abstract boolean doAction(FTPClient client); public boolean isSuccessed() { return isOK; } public String getError() { return error; } } static class DeleteDirCommand extends FTPCommand { private String remotePath; public DeleteDirCommand(String remotePath) { this.remotePath = remotePath; } @Override public boolean doAction(FTPClient client) { try { FTPFile[] files = client.listFiles(remotePath); if (files == null || files.length == 0) return client.removeDirectory(remotePath); for (FTPFile file : files) { if (file.isDirectory()) deleteChildren(client, remotePath + "/" + file.getName()); else client.dele(remotePath + "/" + file.getName()); } return client.removeDirectory(remotePath); } catch (Exception exp) { error = "failed to delete dirctory " + remotePath + " in FTP server because " + exp.getMessage(); log.warn(error, exp); return false; } } private boolean deleteChildren(FTPClient client, String pathName) { try { FTPFile[] files = client.listFiles(pathName); if (files == null || files.length == 0) return client.removeDirectory(pathName); for (FTPFile file : files) { if (file.isDirectory()) deleteChildren(client, pathName + "/" + file.getName()); else client.dele(pathName + "/" + file.getName()); } return client.removeDirectory(pathName); } catch (Exception exp) { error = "failed to delete dirctory " + remotePath + "in FTP server because " + exp.getMessage(); log.warn(error, exp); return false; } } } static class DeleteFileCommand extends FTPCommand { private String remoteFilePath; public DeleteFileCommand(String remoteFilePath) { this.remoteFilePath = remoteFilePath; } @Override public boolean doAction(FTPClient client) { try { FTPFile[] files = client.listFiles(remoteFilePath); if (files == null || files.length == 0) return true; else return client.deleteFile(remoteFilePath); } catch (Exception exp) { error = "failed to delete file " + remoteFilePath + " in FTP server because " + exp.getMessage(); log.warn(error, exp); return false; } } } }特别提示:PropertiesUtil这个类是我自己读取配置文件的类,就不贴代码了,
至此,大功告成!!!
FTP连接池的更多相关文章
- 使用commons-pool2实现FTP连接池
GitHub : https://github.com/jayknoxqu/ftp-pool 一. 连接池概述 频繁的建立和关闭连接,会极大的降低系统的性能,而连接池会在初始化的时候会创建一定 ...
- Java 自定义FTP连接池
转自:https://blog.csdn.net/eakom/article/details/79038590 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn ...
- JAVA ftp连接池功能实现
抽象类: package com.echo.store; import java.util.Enumeration; import java.util.Hashtable; abstract clas ...
- SpringBoot整合自定义FTP文件连接池
说明:通过GenericObjectPool实现的FTP连接池,记录一下以供以后使用环境:JDK版本1.8框架 :springboot2.1文件服务器: Serv-U1.引入依赖 <!--ftp ...
- 连接SQLServer时,因启用连接池导致孤立事务的原因分析和解决办法
本文出处:http://www.cnblogs.com/wy123/p/6110349.html 之前遇到过这么一种情况: 连接数据库的部分Session会出现不定时的阻塞,这种阻塞时长时短,有时候持 ...
- C3p0连接池配置
在Java开发中,使用JDBC操作数据库的四个步骤如下: ①加载数据库驱动程序(Class.forName("数据库驱动类");) ②连接数据库(Connection co ...
- Java第三方数据库连接池库-DBCP-C3P0-Tomcat内置连接池
连接池原理 数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”.预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去.我们可以通过设定连接池 ...
- common-pool2 学习:thrift连接池的另一种实现
对象池是一种很实用的技术,经典的例子就是数据库连接池.去年曾经从零开始写过一个thrift客户端连接池.如果不想重造轮子,可以直接在apache开源项目commons-pool的基础上开发. 步骤: ...
- druid连接池获取不到连接的一种情况
数据源一开始配置: jdbc.initialSize=1jdbc.minIdle=1jdbc.maxActive=5 程序运行一段时间后,执行查询抛如下异常: exception=org.mybati ...
随机推荐
- ruby写一个文件内容相似性比较的代码
1.相似度定义 我们定义,则,我们设,则,|C|=s,则相似度p=,p(0,1) 2.相似度检测算法设计 算法设计: 定义4个字符为一个字符串,将T1,T2分割成若干字符串,若剩余字符不足4个,则以空 ...
- 我的摸索过程之IIS下配置asp.net 的注意事项
"在应用程序级别之外使用注册为 allowDefinition='MachineToApplication' 的节是错误的.如果在 IIS 中没有将虚拟目录配置为应用程序,则可能导致此错误. ...
- 容器(list集合)
--为什么使用集合而不使用数组?why ·集合和数组相似点:都可以存储多个对象,对外作为一个整体存在: ··数组的缺点:1.长度必须在初始化时指定,且固定不变: 2.数组采用连续存储空间,删除和添加元 ...
- Unknown entity: org.jbpm.services.task.audit.TaskEventImpl
1. use this persistence.xml - simply copy it into src/main/resources/META-INF please note the name o ...
- 用js来实现那些数据结构15(图01)
其实在上一篇介绍树结构的时候,已经有了一些算法的相关内容介入.而在图这种数据结构下,会有更多有关图的算法,比如广度优先搜索,深度优先搜索最短路径算法等等.这是我们要介绍的最后一个数据结构.同时也是本系 ...
- DDGScreenShot — 复杂屏幕截屏(如view ScrollView webView wkwebView)
写在前面 最近有这么一个需求,分享页面,分享的是web订单截图,既然是web 就会有超出屏幕的部分, 生成的图片还要加上我们的二维码,这就涉及到图片的合成了. 有了这样的需求,就是各种google.也 ...
- 学生管理系统_排序后通过name删除列表里的字典
l = [{'name': 'wangfan', 'age': 18, 'sex': 'nan'}, {'name': 'wangerfan', 'age': 10, 'sex': 'nan'}, { ...
- 重温《STL源码剖析》笔记 第六、七、八章 next_permutation (字典序)
源码之前,了无秘密 ——侯杰 第六章算法 next_permutation 比如:01342 -> 01423 -> 01432 方法:从尾端开始往前寻找两个相邻的元素,令第一个元素为* ...
- 银行卡号、电话号、身份证号 EditText 自定义格式的输入框
package com.yidian.AddSpaceEditText;import android.text.Editable;import android.text.InputFilter;imp ...
- BOM,DOM常见操作和DHML
BOM (Browser Object Model)浏览器对象模型,控制浏览器的一些行为 window对象 代表一个HTML文档 属性 页面导航的5个属性 self, parent, top, ope ...