使用jsch进行sftp传输时遇到的问题com.jcraft.jsch.JSchException: Session.connect: java.net.SocketException: Connection reset

在做某个业务时,需要将文件传输到另一台服务器,指定使用sftp方式;于是在网上找到jsch包使用,原先代码大致如下:

 1 ChannelSftp channelSftp = null;
 2         try {
 3             JSch jsch = new JSch();
 4             jsch.getSession("ftpUserName", "ftpHost", 22);
 5             Session sshSession = jsch.getSession("ftpUserName", "ftpHost", 22);
 6             System.out.println("Session created.");
 7             sshSession.setPassword("ftpPassword");
 8             Properties sshConfig = new Properties();
 9             sshConfig.put("StrictHostKeyChecking", "no");
10             sshSession.setConfig(sshConfig);
11             sshSession.connect();
12             System.out.println("Session connected.");
13             System.out.println("Opening Channel.");
14             Channel channel = sshSession.openChannel("sftp");
15             channel.connect();
16             channelSftp = (ChannelSftp) channel;
17 
18             //todo 上传文件
19         } catch (Exception e) {
20             //todo 异常处理
21         } finally {
22             //断开sftp连接
23             if (channelSftp != null) {
24                 channelSftp.disconnect();
25             }
26         }

程序运行后大约过了几天,发现日志产生大量连接异常的日志,主要是两类异常:SocketException和NoRouteToHostException

com.jcraft.jsch.JSchException: Session.connect: java.net.SocketException: Connection reset
    at com.jcraft.jsch.Session.connect(Session.java:534)
    at com.jcraft.jsch.Session.connect(Session.java:162)
    at sun.reflect.GeneratedMethodAccessor37.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84)
    at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)



com.jcraft.jsch.JSchException: java.net.NoRouteToHostException: Cannot assign requested address (Address not available) at com.jcraft.jsch.Util.createSocket(Util.java:344) at com.jcraft.jsch.Session.connect(Session.java:194) at com.jcraft.jsch.Session.connect(Session.java:162) at sun.reflect.GeneratedMethodAccessor37.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84) at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) Caused by: java.net.NoRouteToHostException: Cannot assign requested address (Address not available) at java.net.PlainSocketImpl.socketConnect(Native Method) at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206) at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) at java.net.Socket.connect(Socket.java:589) at java.net.Socket.connect(Socket.java:538) at java.net.Socket.<init>(Socket.java:434) at java.net.Socket.<init>(Socket.java:211) at com.jcraft.jsch.Util.createSocket(Util.java:338) ... 17 common frames omitted
 

首先我百度了下,找到有人提到修改socket连接的配置,于是我尝试修改:

1. 修改端口释放后的等待时间为30s。echo 30 > /proc/sys/net/ipv4/tcp_fin_timeout

2. 修改/proc/sys/net/ipv4/tcp_tw_reuse为1。echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse

3. 修改/proc/sys/net/ipv4/tcp_tw_recycle为1。echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle

4.增加可用端口  vim /etc/sysctl.conf 

net.ipv4.ip_local_port_range = 10000     65000      -----意味着10000~65000端口可用 

改完后,执行命令“sysctl -p”使参数生效。

 

修改配置后,重启程序,发现过了一天,仍然出现上述的问题;继续百度查看,发现有人提到连接关闭的问题,于是查了下服务器的ssh连接数

netstat |grep ssh |wc -l

这一查,发现有5500多个连接未关闭(随着时间推移,空闲连接会自动关闭),于是问题的原因大致定位到了:程序生成连接的速度大于连接释放的速度;但是问题的根源还是在于,程序没有正确关闭连接。

不仅仅要断开channel,还要断开session。修改后的代码如下:

 1 ChannelSftp channelSftp = null;
 2         try {
 3             JSch jsch = new JSch();
 4             jsch.getSession("ftpUserName", "ftpHost", 22);
 5             Session sshSession = jsch.getSession("ftpUserName", "ftpHost", 22);
 6             System.out.println("Session created.");
 7             sshSession.setPassword("ftpPassword");
 8             Properties sshConfig = new Properties();
 9             sshConfig.put("StrictHostKeyChecking", "no");
10             sshSession.setConfig(sshConfig);
11             sshSession.connect();
12             System.out.println("Session connected.");
13             System.out.println("Opening Channel.");
14             Channel channel = sshSession.openChannel("sftp");
15             channel.connect();
16             channelSftp = (ChannelSftp) channel;
17 
18             //todo 上传文件
19         } catch (Exception e) {
20             //todo 异常处理
21         } finally {
22             //断开sftp连接
23             if (channelSftp != null) {
24                 try {
25                     channelSftp.disconnect();
26                     //关闭会话
27                     Session session = channelSftp.getSession();
28                     if (session != null) {
29                         session.disconnect();
30                     }
31                 } catch (Exception e) {
32                     //todo 异常处理
33                 }
34             }
35         }

重新运行,观察ssh连接数,发现恢复正常,每次文件传输完毕后,会话及时结束。

posted @ 2022-07-12 17:04  yjry-th  阅读(8792)  评论(0编辑  收藏  举报