前言
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