如何解决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配置,可能引发配置异常。
修复步骤
全局配置初始化移至静态代码块
避免每次创建连接时重复添加ssh-rsa到全局配置,防止配置冗余:static { JSch.setConfig("server_host_key", JSch.getConfig("server_host_key") + ",ssh-rsa"); JSch.setConfig("PubkeyAcceptedAlgorithms", JSch.getConfig("PubkeyAcceptedAlgorithms") + ",ssh-rsa"); }重构连接创建逻辑,单独管理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; }在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(); } } }可选优化:使用连接池
若请求频率较高,可引入SFTP连接池(如基于Apache Commons Pool实现),复用连接以提升性能,同时严格控制连接数量,避免超出服务器限制。
内容的提问来源于stack exchange,提问作者Vrushaket Chaudhari
相关产品推荐
相关产品推荐

