FTPClient自定义连接池实现

版权声明:本文为博主原创文章,欢迎转载,转载请注明作者、原文超链接。 https://blog.csdn.net/axing2015/article/details/85676148

最新在工作当中使用到了ftp服务器,我是使用org.apache.commons.net.ftp.FTPClient做的连接,但是在测试调用的时候经常报断开的管道错误,就此问题我做了一些分析和总结,是因为在调用的时候我只new了一个对象,而使用了多线程进行调用,也就是同一个对象进行了多次调用,而每次调用都有调disconnect()方法,所有再调用的时候就报了断开的管道错误。

  • 针对上面的问题,我首先想到了使用连接池来避免这种底层的错误,而FTPClient没有提供连接池,就此我就手工写了一个连接池。
  • 下面是实现代码,总共用三个类,在实际使用的时候需要根据业务场景做一些轻微的修改。
    • FTPClientConnectPool:FTPClinet 连接池抽象类
    • FTPClientConnectPoolImpl:FTPClient 连接池具体实现类
    • ConnectTest:连接测试类
package com.jin.demo.lock;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;

import java.io.IOException;
import java.util.LinkedList;

/**
 * FTPClinet 连接池抽象类
 *
 * @auther jinsx
 * @date 2019-01-02 10:24
 */
public abstract class FTPClientConnectPool {
    /**
     * 默认最小连接数
     */
    protected int initCount = 3;
    /**
     * 默认最大连接数
     */
    protected int initMaxCount = 5;
    /**
     * 当前正在使用的连接数
     */
    protected int connectCount = 0;
    /**
     * 获取连接默认等待超时时间
     */
    protected Long waitTime = 10000L;
    /**
     * 获取锁默认等待超时时间,防止死锁
     */
    protected Long waitTimeLock = 30000L;
    /**
     * hostname
     */
    protected String hostname = "192.168.0.100";
    /**
     * port
     */
    protected int port = 21;
    /**
     * username
     */
    protected String username = "jin01";
    /**
     * password
     */
    protected String password = "123456";
    /**
     * ftp默认工作目录
     */
    protected String path = "/";
    /**
     * 定义存放FTPClient的连接池
     */
    protected LinkedList<FTPClient> pool = new LinkedList<>();


    /**
     * 获取FTPClient连接对象
     *
     * @return
     */
    protected abstract FTPClient getFTPClient();

    /**
     * 释放FTPClient连接对象
     *
     * @param ftp
     */
    protected abstract void releaseFTPClient(FTPClient ftp);

    /**
     * 初始化FTPClient连接对象
     *
     * @return
     */
    protected FTPClient initFTPClient() {
        FTPClient ftp = new FTPClient();
        try {
            ftp.connect(hostname, port);
            if(!FTPReply.isPositiveCompletion(ftp.getReplyCode())){
                ftp.disconnect();
                System.out.println("FTPServer refused connection");
            }
            boolean login = ftp.login(username, password);
            if(!login){
                ftp.disconnect();
                System.out.println("FTPServer login failed");
            }
            ftp.setControlEncoding("UTF-8");
            ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
            ftp.changeWorkingDirectory(path);
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("initFTPClient result : " + ftp.getReplyString());
        return ftp;
    }

    /**
     * 销毁FTPClient连接对象
     *
     * @param ftp
     */
    protected void destroyFTPClient(FTPClient ftp) {
        try {
            if (ftp != null && ftp.isConnected()) {
                ftp.logout();
            }
        } catch (IOException io) {
            io.printStackTrace();
        } finally {
            // 注意,一定要在finally代码中断开连接,否则会导致占用ftp连接情况
            try {
                if (ftp != null) {
                    ftp.disconnect();
                }
            } catch (IOException io) {
                io.printStackTrace();
            }
        }
    }

    /**
     * 验证FTPClient是否可用
     * @param ftp
     * @return
     */
    protected boolean validateFTPClient(FTPClient ftp) {
        try {
            return ftp.sendNoOp();
        } catch (IOException e) {
            throw new RuntimeException("Failed to validate client: " + e, e);
        }
    }
    public int getInitCount() {
        return initCount;
    }
    public void setInitCount(int initCount) {
        this.initCount = initCount;
    }
    public int getInitMaxCount() {
        return initMaxCount;
    }
    public void setInitMaxCount(int initMaxCount) {
        this.initMaxCount = initMaxCount;
    }
    public int getConnectCount() {
        return connectCount;
    }
    public void setConnectCount(int connectCount) {
        this.connectCount = connectCount;
    }
    public Long getWaitTime() {
        return waitTime;
    }
    public void setWaitTime(Long waitTime) {
        this.waitTime = waitTime;
    }
    public Long getWaitTimeLock() {
        return waitTimeLock;
    }
    public void setWaitTimeLock(Long waitTimeLock) {
        this.waitTimeLock = waitTimeLock;
    }
    public String getHostname() {
        return hostname;
    }
    public void setHostname(String hostname) {
        this.hostname = hostname;
    }
    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 LinkedList<FTPClient> getPool() {
        return pool;
    }
    public void setPool(LinkedList<FTPClient> pool) {
        this.pool = pool;
    }
}
package com.jin.demo.lock;

import org.apache.commons.net.ftp.FTPClient;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * FTPClient 连接池具体实现类
 *
 * @auther jinsx
 * @date 2019-01-02 10:46
 */
public class FTPClientConnectPoolImpl extends FTPClientConnectPool {

    private static final FTPClientConnectPoolImpl FTP_CLIENT_CONNECT_POOL = new FTPClientConnectPoolImpl();
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    /***
     * 私有构造器,并初始化FTPClient连接池
     */
    private FTPClientConnectPoolImpl() {
        for (int i = 0; i < super.initCount; i++) {
            FTPClient ftp = super.initFTPClient();
            super.pool.addLast(ftp);
        }
    }

    /**
     * 提供对外获取实例的静态方法
     *
     * @return
     */
    public static FTPClientConnectPoolImpl getInstance() {
        return FTP_CLIENT_CONNECT_POOL;
    }

    @Override
    protected FTPClient getFTPClient() {
        lock.lock();
        try {
            // 1.计算超时结束时间
            Long endTime = System.currentTimeMillis() + waitTime;
            while (endTime >= System.currentTimeMillis()) {
                if (super.pool.isEmpty()) {
                    // 2.连接池中没有连接对象,进入等待
                    System.out.println(Thread.currentThread().getName() + "进入等待");
                    condition.await(endTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
                }
                if (!super.pool.isEmpty()) {
                    // 3.从连接池中取出一个连接对象
                    FTPClient ftp = pool.removeFirst();
                    // 4.验证是否可用
                    if (super.validateFTPClient(ftp)) {
                        return ftp;
                    } else {
                        // 5.销毁不可用连接对象
                        super.destroyFTPClient(ftp);
                        // 6.重新创建一个连接对象
                        return super.initFTPClient();
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
        // 4.返回null或抛出异常
        System.out.println(Thread.currentThread().getName() + "获取超时返回null");
        return null;
    }

    @Override
    protected void releaseFTPClient(FTPClient ftp) {
        lock.lock();
        try {
            // 1.如果连接池没有满,并且ftp可用,则放到连接池中
            if (super.pool.size() < super.initCount && ftp != null && super.validateFTPClient(ftp)) {
                ftp.changeWorkingDirectory(super.path);
                super.pool.addLast(ftp);
            } else {
                super.destroyFTPClient(ftp);
            }
            // 2.如果连接池有连接,则唤醒一个等待
            if (!super.pool.isEmpty()) {
                condition.signal();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
package com.jin.demo.lock;

import org.apache.commons.net.ftp.FTPClient;

/**
 * 连接测试类
 * @auther jinsx
 * @date 2019-01-02 09:10
 */
public class ConnectTest {

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            Thread.sleep(1000);
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + "前" + System.currentTimeMillis());
                    FTPClientConnectPoolImpl pool = FTPClientConnectPoolImpl.getInstance();
                    FTPClient ftp = pool.getFTPClient();
                    try {
                        Thread.sleep(10000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "后" + System.currentTimeMillis() + ftp);
                    pool.releaseFTPClient(ftp);
                }
            }).start();
        }
    }

}

猜你喜欢

转载自blog.csdn.net/axing2015/article/details/85676148
今日推荐