You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决JSch 0.2.17连接SFTP时的SSH_MSG_DISCONNECT:11报错?

问题描述

使用环境

jsch 0.2.17

相关代码

private ChannelSftp setupJsch() throws JSchException {
    Properties config = new Properties();
    config.put("StrictHostKeyChecking", "no");

    JSch jsch = new JSch();
    jsch.addIdentity(SFTP_PRIVATE_KEY_PATH, SFTP_PRIVATE_KEY_PASSPHRASE);
    JSch.setConfig("server_host_key", JSch.getConfig("server_host_key") + ",ssh-rsa");
    JSch.setConfig("PubkeyAcceptedAlgorithms", JSch.getConfig("PubkeyAcceptedAlgorithms") + ",ssh-rsa");
    Session jschSession = jsch.getSession(SFTP_USERNAME, SFTP_HOST, SFTP_PORT);
    jschSession.setPassword(SFTP_PASSWORD);
    jschSession.setConfig(config);
    jschSession.connect();
    return (ChannelSftp) jschSession.openChannel("sftp");
}
public void getFiles(String sftpDirectoryPath) throws JSchException, SftpException, IOException {
       
    ChannelSftp channelSftp = null;
    LinkedHashMap<String, byte[]> fileBytesMap = new LinkedHashMap<>();
    try {
        channelSftp = setupJsch();
        channelSftp.connect();

        log.info("Fetching files from : " + sftpDirectoryPath);
        Vector<ChannelSftp.LsEntry> files = channelSftp.ls(sftpDirectoryPath);
   }
}

问题现象

功能最初1-2次可正常获取SFTP文件,但之后持续抛出异常com.jcraft.jsch.JSchException: SSH_MSG_DISCONNECT: 11 Application error en-US;每次重启应用后,功能可正常处理部分请求,但之后再次出现错误,直到重启。

异常堆栈日志

2024-10-24T13:02:53.181+05  0 ERROR 13364 --- [ scheduling-1] o.s.s.s.TaskUtils$LoggingErrorHandler : Unexpected error occurred in scheduled task
com.jcraft.jsch.JSchSessionDisconnectException: SSH_MSG_DISCONNECT: 11 Application error en-US
 at com.jcraft.jsch.Session.read(Session.java:1316) ~[jsch-0.2.17.jar!/:0.2.17]
 at com.jcraft.jsch.Session.connect(Session.java  39) ~[jsch-0.2.17.jar!/:0.2.17]
 at com.jcraft.jsch.Session.connect(Session.java:19  ~[jsch-0.2.17.jar!/:0.2.17]
 at com.abc.xyz.util.SFTPUtil.setupJsch(SFTPUtil.java:79) ~[classes!/:0.0.1-SNAPSHOT]
 at com.abc.xyz.util.SFTPUtil.getFiles(SFTPUtil.java:93) ~[classes!/:0.0.1-SNAPSHOT]
 at com.abc.xyz.listener.firm.firmH2HListener.getBankFolderFiles(firmH2HListener.java  6) ~[classes!/:0.0.1-SNAPSHOT]
 at jdk.internal.reflect.GeneratedMethodAccessor22.invoke(Unknown Source) ~[na:na]
 at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
 at java.base/java.lang.reflect.Method.invoke(Method.java:56  ~[na:na]
 at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84) ~[spring-context-6.0.18.jar!/:6.0.18]
 at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) ~[spring-context-6.0.18.jar!/:6.0.18]
 at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) ~[na:na]
 at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java  05) ~[na:na]
 at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java  05) ~[na:na]
 at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[na:na]
 at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[na:na]
 at java.base/java.lang.Thread.run(Thread.java:842) ~[na:na]
2024-10-24T13:02:53.181+05  0 ERROR 13364 --- [ scheduling-1] o.s.s.s.TaskUtils$LoggingErrorHandler : Unexpected error occurred in scheduled task

com.jcraft.jsch.JSchSessionDisconnectException: SSH_MSG_DISCONNECT: 11 Application error en-US
 at com.jcraft.jsch.Session.read(Session.java:1316) ~[jsch-0.2.17.jar!/:0.2.17]
 at com.jcraft.jsch.Session.connect(Session.java  39) ~[jsch-0.2.17.jar!/:0.2.17]
 at com.jcraft.jsch.Session.connect(Session.java:19  ~[jsch-0.2.17.jar!/:0.2.17]
 at com.abc.xyz.util.SFTPUtil.setupJsch(SFTPUtil.java:79) ~[classes!/:0.0.1-SNAPSHOT]
 at com.abc.xyz.util.SFTPUtil.getFiles(SFTPUtil.java:93) ~[classes!/:0.0.1-SNAPSHOT]
 at com.abc.xyz.listener.firm.firmH2HListener.getBankFolderFiles(firmH2HListener.java  6) ~[classes!/:0.0.1-SNAPSHOT]
 at jdk.internal.reflect.GeneratedMethodAccessor22.invoke(Unknown Source) ~[na:na]
 at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
 at java.base/java.lang.reflect.Method.invoke(Method.java:56  ~[na:na]
 at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84) ~[spring-context-6.0.18.jar!/:6.0.18]
 at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) ~[spring-context-6.0.18.jar!/:6.0.18]
 at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) ~[na:na]
 at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java  05) ~[na:na]
 at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java  05) ~[na:na]
 at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[na:na]
 at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[na:na]
 at java.base/java.lang.Thread.run(Thread.java:842) ~[na:na]
t com.jcraft.jsch.Session.read(Session.java:1316) ~[jsch-0.2.17.jar!/:0.2.17]
 at com.jcraft.jsch.Session.connect(Session.java  39) ~[jsch-0.2.17.jar!/:0.2.17]
 at com.jcraft.jsch.Session.connect(Session.java:19  ~[jsch-0.2.17.jar!/:0.2.17]
 at com.abc.xyz.util.SFTPUtil.setupJsch(SFTPUtil.java:79) ~[classes!/:0.0.1-SNAPSHOT]
 at com.abc.xyz.util.SFTPUtil.getFiles(SFTPUtil.java:93) ~[classes!/:0.0.1-SNAPSHOT]
 at com.abc.xyz.listener.firm.firmH2HListener.getInboxFolderFiles(firmH2HListener.java:41) ~[classes!/:0.0.1-SNAPSHOT]
 at jdk.internal.reflect.GeneratedMethodAccessor22.invoke(Unknown Source) ~[na:na]
 at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
 at java.base/java.lang.reflect.Method.invoke(Method.java:56  ~[na:na]
 at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84) ~[spring-context-6.0.18.jar!/:6.0.18]
 at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) ~[spring-context-6.0.18.jar!/:6.0.18]
 at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) ~[na:na]
 at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java  05) ~[na:na]
 at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java  05) ~[na:na]
 at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[na:na]
 at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[na:na]
 at java.base/java.lang.Thread.run(Thread.java:842) ~[na:na]
解决方案

核心问题

代码未正确释放SSH会话和SFTP通道,导致服务器端连接数耗尽,后续请求无法建立新连接;同时重复修改全局JSch配置,可能引发配置异常。

修复步骤

  1. 全局配置初始化移至静态代码块
    避免每次创建连接时重复添加ssh-rsa到全局配置,防止配置冗余:

    static {
        JSch.setConfig("server_host_key", JSch.getConfig("server_host_key") + ",ssh-rsa");
        JSch.setConfig("PubkeyAcceptedAlgorithms", JSch.getConfig("PubkeyAcceptedAlgorithms") + ",ssh-rsa");
    }
    
  2. 重构连接创建逻辑,单独管理Session
    修改setupJsch返回Session,便于后续统一释放资源:

    private Session setupJsch() throws JSchException {
        Properties config = new Properties();
        config.put("StrictHostKeyChecking", "no");
    
        JSch jsch = new JSch();
        jsch.addIdentity(SFTP_PRIVATE_KEY_PATH, SFTP_PRIVATE_KEY_PASSPHRASE);
        Session jschSession = jsch.getSession(SFTP_USERNAME, SFTP_HOST, SFTP_PORT);
        jschSession.setPassword(SFTP_PASSWORD);
        jschSession.setConfig(config);
        jschSession.connect(30000); // 设置30秒连接超时,避免无限等待
        return jschSession;
    }
    
  3. 在finally块中强制释放资源
    确保每次请求完成后关闭SFTP通道和SSH会话,避免连接泄漏:

    public void getFiles(String sftpDirectoryPath) throws JSchException, SftpException, IOException {
        Session jschSession = null;
        ChannelSftp channelSftp = null;
        LinkedHashMap<String, byte[]> fileBytesMap = new LinkedHashMap<>();
        try {
            jschSession = setupJsch();
            channelSftp = (ChannelSftp) jschSession.openChannel("sftp");
            channelSftp.connect();
    
            log.info("Fetching files from : " + sftpDirectoryPath);
            Vector<ChannelSftp.LsEntry> files = channelSftp.ls(sftpDirectoryPath);
            // 此处添加文件处理逻辑
        } finally {
            // 优先关闭SFTP通道
            if (channelSftp != null && channelSftp.isConnected()) {
                channelSftp.disconnect();
            }
            // 再关闭SSH会话
            if (jschSession != null && jschSession.isConnected()) {
                jschSession.disconnect();
            }
        }
    }
    
  4. 可选优化:使用连接池
    若请求频率较高,可引入SFTP连接池(如基于Apache Commons Pool实现),复用连接以提升性能,同时严格控制连接数量,避免超出服务器限制。

内容的提问来源于stack exchange,提问作者Vrushaket Chaudhari

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 03:04:51