SFTP使用JSCH库链接不断开解决方法

在处理银行业务的时候,数据交互还使用老旧的sftp技术,最近在使用sftp的JSCH库时发现,采用公私钥方式连接server,总是无法断开连接,研究发现这种模式下如果存在并发的链接时,disconnect方法实际不起左右,这样会产生大量链接,最终造成无法再链接上;解决办法采用Threadlocal镜像复制方式,为每个链接建立单独的工具对象


public class SftpUtil {
    private final static Logger          log       = LoggerFactory.getLogger(SftpUtil.class);

    /** SFTP */
    public static final String           SFTP      = "sftp";
    /** 通道 */
    private ChannelSftp                  channel;
    /** session */
    private Session                      session;

    /** 规避多线程并发不断开问题 */
    private static ThreadLocal<SftpUtil> sftpLocal = new ThreadLocal<SftpUtil>();

    /**
     * 获取sftpchannel
     * 
     * @param connectConfig 连接配置
     * @return
     * @throws Exception 
     * @throws JSchException
     */
    private void init(ConnectConfig connectConfig) throws Exception {
        String host = connectConfig.getHost();
        int port = connectConfig.getPort();

        String userName = connectConfig.getUserName();

        //创建JSch对象
        JSch jsch = new JSch();

        //添加私钥(信任登录方式)
        if (StringUtils.isNotBlank(connectConfig.getPrivateKey())) {
            jsch.addIdentity(connectConfig.getPrivateKey());
        }

        session = jsch.getSession(userName, host, port);
        if (log.isInfoEnabled()) {
            log.info(" JSCH Session created,sftpHost = {}, sftpUserName={}", host, userName);
        }

        //设置密码
        if (StringUtils.isNotBlank(connectConfig.getPassWord())) {
            session.setPassword(connectConfig.getPassWord());
        }

        Properties config = new Properties();
        config.put("StrictHostKeyChecking", "no");
        session.setConfig(config);
        //设置超时
        session.setTimeout(connectConfig.getTimeout());
        //建立连接
        session.connect();
        if (log.isInfoEnabled()) {
            log.info("JSCH Session connected.sftpHost = {}, sftpUserName={}", host, userName);
        }

        //打开SFTP通道
        channel = (ChannelSftp) session.openChannel(SFTP);
        //建立SFTP通道的连接
        channel.connect();
        if (log.isInfoEnabled()) {
            log.info("Connected successfully to sftpHost = {}, sftpUserName={}", host, userName);
        }
    }

    /**
     * 是否已连接
     * 
     * @return
     */
    private boolean isConnected() {
        return null != channel && channel.isConnected();
    }

    /**
     * 获取本地线程存储的sftp客户端
     * 
     * @return
     * @throws Exception 
     */
    public static SftpUtil getSftpUtil(ConnectConfig connectConfig) throws Exception {
        SftpUtil sftpUtil = sftpLocal.get();
        if (null == sftpUtil || !sftpUtil.isConnected()) {
            sftpLocal.set(new SftpUtil(connectConfig));
        }
        return sftpLocal.get();
    }

    /**
     * 释放本地线程存储的sftp客户端
     */
    public static void release() {
        if (null != sftpLocal.get()) {
            sftpLocal.get().closeChannel();
            sftpLocal.set(null);
        }
    }

    /**
     * 构造函数
     * <p>
     * 非线程安全,故权限为私有
     * </p>
     * 
     * @throws Exception 
     */
    private SftpUtil(ConnectConfig connectConfig) throws Exception {
        super();
        init(connectConfig);
    }

    /**
     * 关闭通道
     * 
     * @throws Exception
     */
    public void closeChannel() {
        if (null != channel) {
            try {
                channel.disconnect();
            } catch (Exception e) {
                log.error("关闭SFTP通道发生异常:", e);
            }
        }
        if (null != session) {
            try {
                session.disconnect();
            } catch (Exception e) {
                log.error("SFTP关闭 session异常:", e);
            }
        }
    }

    /**
     * 下载文件
     * 
     * @param downDir 下载目录
     * @param src 源文件
     * @param dst 保存后的文件名称或目录
     * @throws Exception
     */
    public void downFile(String downDir, String src, String dst) throws Exception {
        channel.cd(downDir);
        channel.get(src, dst);
    }

    /**
     * 删除文件
     * 
     * @param filePath 文件全路径
     * @throws SftpException
     */
    public void deleteFile(String filePath) throws SftpException {
        channel.rm(filePath);
    }

    @SuppressWarnings("unchecked")
    public List<String> listFiles(String dir) throws SftpException {
        Vector<LsEntry> files = channel.ls(dir);
        if (null != files) {
            List<String> fileNames = new ArrayList<String>();
            Iterator<LsEntry> iter = files.iterator();
            while (iter.hasNext()) {
                String fileName = iter.next().getFilename();
                if (StringUtils.equals(".", fileName) || StringUtils.equals("..", fileName)) {
                    continue;
                }
                fileNames.add(fileName);
            }
            return fileNames;
        }
        return null;
    }
}

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bbkkkk

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值