当前位置: 首页 > 工具软件 > JSch > 使用案例 >

jsch中的sftp

羊舌自强
2023-12-01

SFTP相关的api说实话还是挺好用的,不过也有不少的坑。

直接上问题吧:timeout: socket is not established

当时是突然爆出来的问题,之前登陆sftp都没出过问题,突然生产报出来了。我透,这有点恶心人。

我在网上翻过挺多文章的,都没怎么看到解决方案,于是我就自力更生,看了下源码。算了再回头说下问题现状吧,

问题现状是:在登陆的时候,session.connect(30*1000);给会话设置了连接超时时间,当时都没多想,感觉没啥问题。

当问题出来,我跟进源码发现了有一个方法:

Util.createSocket(this.host, this.port, connectTimeout);

这个方法就是获取句柄的入口方法,我们继续跟下去:

static Socket createSocket(final String host, final int port, int timeout) throws JSchException {
        Socket socket = null;
        if (timeout == 0) {
            try {
                socket = new Socket(host, port);
                return socket;
            } catch (Exception var12) {
                String message = var12.toString();
                if (var12 instanceof Throwable) {
                    throw new JSchException(message, var12);
                } else {
                    throw new JSchException(message);
                }
            }
        } else {
            final Socket[] sockp = new Socket[1];
            final Exception[] ee = new Exception[1];
            String message = "";
            Thread tmp = new Thread(new Runnable() {
                public void run() {
                    sockp[0] = null;

                    try {
                        sockp[0] = new Socket(host, port);
                    } catch (Exception var4) {
                        ee[0] = var4;
                        if (sockp[0] != null && sockp[0].isConnected()) {
                            try {
                                sockp[0].close();
                            } catch (Exception var3) {
                                ;
                            }
                        }

                        sockp[0] = null;
                    }

                }
            });
            tmp.setName("Opening Socket " + host);
            tmp.start();

            try {
                tmp.join((long)timeout);
                message = "timeout: ";
            } catch (InterruptedException var11) {
                ;
            }
            
            //超时时,由于socket未完成实例化(或者未连接上sftp),主线程并行时,不符合条件抛出异常
            if (sockp[0] != null && sockp[0].isConnected()) {
                socket = sockp[0];
                return socket;
            } else {
                message = message + "socket is not established";
                if (ee[0] != null) {
                    message = ee[0].toString();
                }

                tmp.interrupt();
                tmp = null;
                throw new JSchException(message, ee[0]);
            }
        }
    }

咱们看一下这个方法:根据设置的超时时间分为两个分支:

第一个分支没什么说的,就是新创建一个对象并返回。

当设置了超时时间时:方法采用的创建线程来处理的方式。

因为在此静态api中,不存在静态变量的操作,所以此方法是线程安全的。

创建的线程都是join(time)到主线程中的,也就是主线程等待至少time才执行。

这里是关键,如果在线程实例化Socket,连接sftp还未完成时,达到了超时时间time,此时主线程会和此线程并行!

并行的结果就是,主线程在句柄为实例化的情况下做了判断,导致抛出异常!

抛出的异常意思是:socket还没有创建出来!

这种情况下一般再调用一次就可以了。如果反复尝试都连不上的话,就有两种可能:

1:sftp端口没赋权导致连接超时

2:网络较差连接耗时大于time

如果是没有赋权,就打通下网络,如果连接耗时过长,我自己的解决方案是:不设置session的超时时间。那么主线程会一直等到线程执行完再执行。要么就报错。

 

 

 

 类似资料: