Jsch session channel timeout 默认连接超时时间机制

导读:本篇文章讲解 Jsch session channel timeout 默认连接超时时间机制,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

前言

Jsch版本

<dependency>
    <groupId>com.jcraft</groupId>
    <artifactId>jsch</artifactId>
    <version>0.1.55</version>
</dependency>

代码示例

public ChannelSftp createChannel() throws JSchException {
    JSch jsch = new JSch();
    Session session = jsch.getSession(username, host, port);
    session.setPassword(password);
    session.setConfig("StrictHostKeyChecking", "no");
    //可设连接超时时间
    session.connect();
    ChannelSftp channel = (ChannelSftp) session.openChannel("sftp");
    //可设连接超时时间
    channel.connect();
    return channel;
}

上面的session和channel连接时都使用了无参构造函数,我看有的人说要穿连接超时限制,但是也没说默认连接超时时间是多久,所以自己得看看,可能他设个5000毫秒,也可能设个-1、0之类的永不超时

源码分析

Session

com.jcraft.jsch.Session

分析

默认时间是0

private int timeout=0;

public void connect() throws JSchException{
    connect(timeout);
}

有多种连接方式,如socket_factory、proxy,如我们看socket_factory的createSocket就行

也可以看到当connectTimeout>0时进行了setSoTimeout设置,所以说这个连接的connectTimeout和soTimeout是取得同一个值,你要网络不好、文件操作时间长,还真不能设短了,要按实际情况设置

public void connect(int connectTimeout) throws JSchException{
    //省略
	if(socket_factory==null){
          socket=Util.createSocket(host, port, connectTimeout);
	  in=socket.getInputStream();
	  out=socket.getOutputStream();
	}
    synchronized(proxy){
          proxy.connect(socket_factory, host, port, connectTimeout);
	  io.setInputStream(proxy.getInputStream());
	  io.setOutputStream(proxy.getOutputStream());
          socket=proxy.getSocket();
	}
      }

      if(connectTimeout>0 && socket!=null){
        socket.setSoTimeout(connectTimeout);
      }
        

这里在timeout为0时直接new Socket,返回socket后在外层设置,默认是0,就是没设置,使用Socket的默认超时时间

java.net.Socket中写了A timeout of zero is interpreted as an infinite timeout. The connection will then block until established or an error occurs,就是无限等待,直到建立连接或发生错误

if(connectTimeout>0 && socket!=null){
  socket.setSoTimeout(connectTimeout);
}

如果不是0,使用了thread的join方法,就是阻塞等待设置的超时时间,超过了就报错

com.jcraft.jsch.SocketFactory中

static Socket createSocket(String host, int port, int timeout) throws JSchException{
  Socket socket=null;
  if(timeout==0){
    try{
      socket=new Socket(host, port);
      return socket;
    }
    catch(Exception e){
      String message=e.toString();
      if(e instanceof Throwable)
        throw new JSchException(message, (Throwable)e);
      throw new JSchException(message);
    }
  }
  final String _host=host;
  final int _port=port;
  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 e){
          ee[0]=e;
          if(sockp[0]!=null && sockp[0].isConnected()){
            try{
              sockp[0].close();
            }
            catch(Exception eee){}
          }
          sockp[0]=null;
        }
      }
    });
  tmp.setName("Opening Socket "+host);
  tmp.start();
  try{ 
    tmp.join(timeout);
    message="timeout: ";
  }
  catch(java.lang.InterruptedException eee){
  }
  if(sockp[0]!=null && sockp[0].isConnected()){
    socket=sockp[0];
  }
  else{
    message+="socket is not established";
    if(ee[0]!=null){
      message=ee[0].toString();
    }
    tmp.interrupt();
    tmp=null;
    throw new JSchException(message, ee[0]);
  }
  return socket;
} 

结论

Session默认使用java.net.Socket的默认超时时间0,会无限等待,直到建立连接或发生错误

Channel

com.jcraft.jsch.Channel

分析

channel直接写死了个0,然后赋给connectTimeout变量,同一个SDK的代码,风格都不一样。。

sendChannelOpen是com.jcraft.jsch.Channel自己的方法,用来打开连接

start是抽象方法,有四个实现:com.jcraft.jsch.ChannelSftp、com.jcraft.jsch.ChannelExec、com.jcraft.jsch.ChannelShell、com.jcraft.jsch.ChannelSubsystem

public void connect() throws JSchException{
  connect(0);
}
public void connect(int connectTimeout) throws JSchException{
    this.connectTimeout=connectTimeout;
    try{
      sendChannelOpen();
      start();
    }
    catch(Exception e){
      connected=false;
      disconnect();
      if(e instanceof JSchException) 
        throw (JSchException)e;
      throw new JSchException(e.toString(), e);
    }
  }

当timeout不是0,只尝试1次,使用Object的wait指定时间

是0的时候,连接成功全重试2000次,每次等10毫秒,也就是20秒

protected void sendChannelOpen() throws Exception {
  Session _session=getSession();
  if(!_session.isConnected()){
    throw new JSchException("session is down");
  }

  Packet packet = genChannelOpenPacket();
  _session.write(packet);

  int retry=2000;
  long start=System.currentTimeMillis();
  long timeout=connectTimeout;
  if(timeout!=0L) retry = 1;
  synchronized(this){
    while(this.getRecipient()==-1 &&
          _session.isConnected() &&
           retry>0){
      if(timeout>0L){
        if((System.currentTimeMillis()-start)>timeout){
          retry=0;
          continue;
        }
      }
      try{
        long t = timeout==0L ? 10L : timeout;
        this.notifyme=1;
        wait(t);
      }
      catch(java.lang.InterruptedException e){
      }
      finally{
        this.notifyme=0;
      }
      retry--;
    }
  }
  if(!_session.isConnected()){
    throw new JSchException("session is down");
  }
  if(this.getRecipient()==-1){  // timeout
    throw new JSchException("channel is not opened.");
  }
  if(this.open_confirmation==false){  // SSH_MSG_CHANNEL_OPEN_FAILURE
    throw new JSchException("channel is not opened.");
  }
  connected=true;
}

结论

Channel连接默认20秒超时

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/93675.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!