在做某个业务时,需要将文件传输到另一台服务器,指定使用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)<br><br><br><br>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连接数,发现恢复正常,每次文件传输完毕后,会话及时结束。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |