使用jsch进行sftp传输时遇到的问题com.jcraft.jsch.JSchException: Session ...

打印 上一主题 下一主题

主题 887|帖子 887|积分 2661

在做某个业务时,需要将文件传输到另一台服务器,指定使用sftp方式;于是在网上找到jsch包使用,原先代码大致如下:
  1. 1 ChannelSftp channelSftp = null;
  2. 2         try {
  3. 3             JSch jsch = new JSch();
  4. 4             jsch.getSession("ftpUserName", "ftpHost", 22);
  5. 5             Session sshSession = jsch.getSession("ftpUserName", "ftpHost", 22);
  6. 6             System.out.println("Session created.");
  7. 7             sshSession.setPassword("ftpPassword");
  8. 8             Properties sshConfig = new Properties();
  9. 9             sshConfig.put("StrictHostKeyChecking", "no");
  10. 10             sshSession.setConfig(sshConfig);
  11. 11             sshSession.connect();
  12. 12             System.out.println("Session connected.");
  13. 13             System.out.println("Opening Channel.");
  14. 14             Channel channel = sshSession.openChannel("sftp");
  15. 15             channel.connect();
  16. 16             channelSftp = (ChannelSftp) channel;
  17. 17
  18. 18             //todo 上传文件
  19. 19         } catch (Exception e) {
  20. 20             //todo 异常处理
  21. 21         } finally {
  22. 22             //断开sftp连接
  23. 23             if (channelSftp != null) {
  24. 24                 channelSftp.disconnect();
  25. 25             }
  26. 26         }
复制代码
程序运行后大约过了几天,发现日志产生大量连接异常的日志,主要是两类异常:SocketException和NoRouteToHostException
  1. com.jcraft.jsch.JSchException: Session.connect: java.net.SocketException: Connection reset
  2.     at com.jcraft.jsch.Session.connect(Session.java:534)
  3.     at com.jcraft.jsch.Session.connect(Session.java:162)
  4.     at sun.reflect.GeneratedMethodAccessor37.invoke(Unknown Source)
  5.     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  6.     at java.lang.reflect.Method.invoke(Method.java:498)
  7.     at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84)
  8.     at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
  9.     at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
  10.     at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
  11.     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
  12.     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
  13.     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
  14.     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
  15.     at java.lang.Thread.run(Thread.java:748)<br><br><br><br>com.jcraft.jsch.JSchException: java.net.NoRouteToHostException: Cannot assign requested address (Address not available)
  16.         at com.jcraft.jsch.Util.createSocket(Util.java:344)
  17.         at com.jcraft.jsch.Session.connect(Session.java:194)
  18.         at com.jcraft.jsch.Session.connect(Session.java:162)
  19.         at sun.reflect.GeneratedMethodAccessor37.invoke(Unknown Source)
  20.         at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  21.         at java.lang.reflect.Method.invoke(Method.java:498)
  22.         at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84)
  23.         at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
  24.         at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
  25.         at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
  26.         at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
  27.         at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
  28.         at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
  29.         at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
  30.         at java.lang.Thread.run(Thread.java:748)
  31. Caused by: java.net.NoRouteToHostException: Cannot assign requested address (Address not available)
  32.         at java.net.PlainSocketImpl.socketConnect(Native Method)
  33.         at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
  34.         at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
  35.         at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
  36.         at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
  37.         at java.net.Socket.connect(Socket.java:589)
  38.         at java.net.Socket.connect(Socket.java:538)
  39.         at java.net.Socket.<init>(Socket.java:434)
  40.         at java.net.Socket.<init>(Socket.java:211)
  41.         at com.jcraft.jsch.Util.createSocket(Util.java:338)
  42.         ... 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. 1 ChannelSftp channelSftp = null;
  2. 2         try {
  3. 3             JSch jsch = new JSch();
  4. 4             jsch.getSession("ftpUserName", "ftpHost", 22);
  5. 5             Session sshSession = jsch.getSession("ftpUserName", "ftpHost", 22);
  6. 6             System.out.println("Session created.");
  7. 7             sshSession.setPassword("ftpPassword");
  8. 8             Properties sshConfig = new Properties();
  9. 9             sshConfig.put("StrictHostKeyChecking", "no");
  10. 10             sshSession.setConfig(sshConfig);
  11. 11             sshSession.connect();
  12. 12             System.out.println("Session connected.");
  13. 13             System.out.println("Opening Channel.");
  14. 14             Channel channel = sshSession.openChannel("sftp");
  15. 15             channel.connect();
  16. 16             channelSftp = (ChannelSftp) channel;
  17. 17
  18. 18             //todo 上传文件
  19. 19         } catch (Exception e) {
  20. 20             //todo 异常处理
  21. 21         } finally {
  22. 22             //断开sftp连接
  23. 23             if (channelSftp != null) {
  24. 24                 try {
  25. 25                     channelSftp.disconnect();
  26. 26                     //关闭会话
  27. 27                     Session session = channelSftp.getSession();
  28. 28                     if (session != null) {
  29. 29                         session.disconnect();
  30. 30                     }
  31. 31                 } catch (Exception e) {
  32. 32                     //todo 异常处理
  33. 33                 }
  34. 34             }
  35. 35         }
复制代码
重新运行,观察ssh连接数,发现恢复正常,每次文件传输完毕后,会话及时结束。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

羊蹓狼

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表