com.jcraft.jsch.JSchException: verify: false

背景

高并发下,SFTP上传偶现com.jcraft.jsch.JSchException: verify: false,网上有说升级版本什么的修复了这个bug,然而升级版本后事实证明这个bug还是会出现,大概上传几百次会出现一次。但是项目不可能允许文件丢失,需要百分百的正确率。

SFTP工具类

package util;
 

import com.jcraft.jsch.*;
import org.springframework.util.StringUtils;

import java.io.InputStream;
import java.util.*;

public class SFTPUtil {


    private ChannelSftp sftp;
 
    private Session session;
    /**
     * SFTP 登录用户名
     */
    private String username;
    /**
     * SFTP 登录密码
     */
    private String password;
    /**
     * SFTP 服务器地址IP地址
     */
    private String host;
    /**
     * SFTP 端口
     */
    private int port;
 
 
    /**
     * 构造基于密码认证的sftp对象
     */
    public SFTPUtil(String username, String password, String host, int port) {
        this.username = username;
        this.password = password;
        this.host = host;
        this.port = port;
    }
 

    public SFTPUtil() {

    }
 
 
    /**
     * 连接sftp服务器
     */
    public void login() {
        try {
            JSch jsch = new JSch();
            session = jsch.getSession(username, host, port);
            if (password != null) {
                session.setPassword(password);
            }
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");
 
            session.setConfig(config);
            session.connect();
 
            Channel channel = session.openChannel("sftp");
            channel.connect();
 
            sftp = (ChannelSftp) channel;
        } catch (Exception e) {
           e.printStackTrace();
        }
    }
 
    /**
     * 关闭连接 server
     */
    public void logout() {
        if (sftp != null) {
            if (sftp.isConnected()) {
                sftp.disconnect();
            }
        }
        if (session != null) {
            if (session.isConnected()) {
                session.disconnect();
            }
        }
    }

    /**
     * 将输入流的数据上传到sftp作为文件。文件完整路径=basePath+directory
     *
     * @param directory    上传到该目录
     * @param sftpFileName sftp端文件名
     * @param is 文件输入流
     */
    public boolean upload(String directory, String sftpFileName, InputStream is){
        try {
            if (!StringUtils.isEmpty(directory)) {
                sftp.cd(directory);
            }
            sftp.put(is, sftpFileName);  //上传文件
            return true;
        } catch (Exception e) {
           e.printStackTrace();
            return false;
        }
    }


}

测试代码


import util.SFTPUtil;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @description:
 * @author:wanzh
 * @date:2022/3/29
 */
public class TestSFTPUtils {
    private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(128, 128, 5, TimeUnit.SECONDS, new ArrayBlockingQueue<>(500));

    public static void main(String[] args) throws InterruptedException {
        testSFTP(500);

    }

    private static void testSFTP(int num) throws InterruptedException {
        long startTime = System.currentTimeMillis();
        AtomicInteger successNum = new AtomicInteger();
        CountDownLatch countDownLatch = new CountDownLatch(num);
        for(int i = 0; i < num; i++){
            threadPoolExecutor.execute(()->{
                boolean flag = false;
                try {
                    File file = new File("D:\\work.jpg");
                    InputStream is = new FileInputStream(file);
                    String directName = "/upload/nvrm/20220107/";
                    SFTPUtil sftpUtil = new SFTPUtil("xxx", "xxx", "xxx", 22);
                    sftpUtil.login();
                    flag = sftpUtil.upload(directName,  UUID.randomUUID()+ ".jpg", is);
                    sftpUtil.logout();
                }catch (Exception e){
                    e.printStackTrace();
                }
                if(flag){
                    successNum.incrementAndGet();
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        threadPoolExecutor.shutdown();
        long endTime = System.currentTimeMillis();
        System.out.println(String.format("总文件数量:%s,成功传输文件数量:%s,花费时间: %s秒",num,successNum.get(),(endTime - startTime)/1000));
    }
}

测试效果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

解决方案

大概思路,首先是上传失败后重试,其次为了提升传输速度,每个线程只登录一次即可,不需要每传输一个文件登录退出。

public class TestSFTPUtils2 {
    private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(128, 128, 5, TimeUnit.SECONDS, new ArrayBlockingQueue<>(500));

    private static ThreadLocal<SFTPUtil> sftpUtilThreadLocal = new ThreadLocal<>();


    public static void main(String[] args) throws InterruptedException {
        testSFTP(500);

    }

    private static void testSFTP(int num) throws InterruptedException {
        long startTime = System.currentTimeMillis();
        AtomicInteger successNum = new AtomicInteger();
        CountDownLatch countDownLatch = new CountDownLatch(num);
        for(int i = 0; i < num; i++){
            threadPoolExecutor.execute(()->{
                boolean flag = false;
                try {
                    File file = new File("D:\\work.jpg");
                    InputStream is = new FileInputStream(file);
                    String directName = "/upload/nvrm/20220107/";
                    flag = upload(  UUID.randomUUID()+ ".jpg", directName,is,1);
                }catch (Exception e){
                    e.printStackTrace();
                }
                if(flag){
                    successNum.incrementAndGet();
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        threadPoolExecutor.shutdown();
        long endTime = System.currentTimeMillis();
        System.out.println(String.format("总文件数量:%s,成功传输文件数量:%s,花费时间: %s秒",num,successNum.get(),(endTime - startTime)/1000));
    }


    /**
     * 传输文件
     * @param fileName 文件名
     * @param directName 目录
     * @param inputStream 文件流
     * @param num 传输次数
     * @return
     */
    public static boolean upload(String fileName, String directName,InputStream inputStream, int num) {
    	if(num > 1){
            System.out.println(String.format("重新上传,文件名:%s,次数:%s",fileName,num));
        }
        SFTPUtil sftpUtil = sftpUtilThreadLocal.get();
        if(sftpUtil == null){
           sftpUtil = new SFTPUtil("xxx", "xxx", "xxxx", 22);
            sftpUtil.login();
            sftpUtilThreadLocal.set(sftpUtil);
        }
        if(num > 3){
            return false;
        }
        boolean upload = sftpUtil.upload(directName, fileName, inputStream);
        if(upload){
            return true;
        }
        sftpUtil.logout();
        sftpUtilThreadLocal.remove();
        sftpUtil = new SFTPUtil("xxx", "xxx", "xxxx", 22);
        sftpUtil.login();
        sftpUtilThreadLocal.set(sftpUtil);
        return upload(fileName,directName,inputStream,num+1);
    }

}

测试效果

在这里插入图片描述
在这里插入图片描述

总结

若文件个数越多,提升速度越明显,项目中解决方案大致如上,这里只是简单模拟测试一下,希望对您有帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值