2013-04-21 255 views
10

我正在編寫使用SSH進行靜態路由管理的Java GUI程序。我的代碼如下:JSch:如何使會話保持活動狀態

import com.jcraft.jsch.*; 
import java.io.*; 

public class Konsep { 
    String status; 
    static String username; 
    static String hostname; 
    String inputcommand; 
    String output; 
    static Session session; 

    JSch jsch = new JSch(); 

    public String status(String stringstatus) { 
     stringstatus = status; 
     return stringstatus; 
    } 

    public String InputCommand(String inputcommandstatus) { 
     inputcommandstatus = inputcommand; 
     return inputcommandstatus; 
    } 

    public void connect(String usernamelokal, String hostnamelokal, 
      String password, int port) { 
     //  JSch jsch=new JSch(); 
     try { 
      Session sessionlokal = jsch.getSession(usernamelokal, 
        hostnamelokal, port); 
      sessionlokal.setPassword(password); 
      UserInfo ui = new UserInfoku.Infoku(); 
      sessionlokal.setUserInfo(ui); 
      sessionlokal.setTimeout(0); 
      sessionlokal.connect(); 
      status = "tersambung \n"; 
      username = usernamelokal; 
      hostname = hostnamelokal; 
      session = sessionlokal; 
      System.out.println(username + " " + hostname); 
     } catch (Exception e) { 
      System.out.println(e); 
      status = "Exception = \n " + e + "\n"; 

     } 
    } 

    public void disconnect() { 
     //  JSch jsch=new JSch(); 
     try { 
      Session sessionlokal = jsch.getSession(username, hostname); 
      //   System.out.println(username +" "+ hostname); 
      sessionlokal.disconnect(); 
      status = "wes pedhoott \n"; 
     } catch (Exception e) { 
      System.out.println(e); 
      status = "Exception = \n " + e + "\n"; 
     } 

    } 

    public void addRoute() { 
     //  JSch jsch=new JSch(); 
     System.out.println(username + " " + hostname); 
     try { 
      Session sessionlokal = session; // =jsch.getSession(username, hostname); 
      Channel channel = sessionlokal.openChannel("exec"); 
      ((ChannelExec) channel).setCommand(inputcommand); 
      channel.setInputStream(null); 
      channel.connect(); 
      ((ChannelExec) channel).setErrStream(System.err); 
      InputStream in = channel.getInputStream(); 
      channel.connect(); 

      byte[] tmp = new byte[1024]; 
      while (true) { 
       while (in.available() > 0) { 
        int i = in.read(tmp, 0, 1024); 
        if (i < 0) 
         break; 
        System.out.print(new String(tmp, 0, i)); 
       } 
       if (channel.isClosed()) { 
        System.out.println("exit-status: " 
          + channel.getExitStatus()); 
        break; 
       } 
       try { 
        Thread.sleep(1000); 
       } catch (Exception ee) { 
       } 
      } 

      channel.disconnect(); 
     } catch (Exception e) { 
      System.out.println(e); 
     } 
    } 
}  

問題是,當我調用connect方法,然後調用addroute,程序返回

root 192.168.50.2 
root 192.168.50.2 
com.jcraft.jsch.JSchException: session is down 

我一直在試圖獲得與會話狀態要麼

Session sessionlokal=session; //returns com.jcraft.jsch.JSchException: ChannelExec 

Session sessionlokal=jsch.getSession(username, hostname); //returns session is down 

我也試過使用keepalive,但它也不工作。

我的意圖是創建一個會話,讓主持人(登錄),同時離開會議,執行一個或多個命令,稍後可能執行其他命令,然後在不需要(註銷)時關閉會話。 我一直在尋找這個論壇,我發現這個question,但代碼是創建一個方法來定義一個命令先執行,然後創建會話,調用命令的方法並關閉會話。

如上所述我該怎麼辦?

回答

10

試圖Session.sendKeepAliveMsg()沒有成功後,我來到了以下解決方案,這似乎是相當穩定:

private Session getSession() throws Exception { 
    try { 
     if (!session.isConnected()) { 
      logger.info("Session nicht konnektiert. Versuche (erneut) zu konnektieren."); 
      session.connect(); 
     } 
    } catch (Throwable t) { 
     logger.info("Session kaputt. Baue neue."); 
     session = jsch.getSession(user, host, port); 
     session.setConfig(config); 
     session.connect(); 
    } 
    return session; 
} 

更新:幾天後,它失敗了。

我試圖通過殺死服務器上的打開會話來測試它。我以前測試過的所有版本都顯示出完全相同的行爲,無論問題在等待幾天或終止服務器進程後都會加劇,所以我認爲這個測試以及上述解決方案的結果是有意義的。不幸的是,它不是。

我會嘗試一些其他方法來修復它並讓您保持最新狀態。

更新2:在生產環境

private Session getSession() throws Exception { 
    try { 
     ChannelExec testChannel = (ChannelExec) session.openChannel("exec"); 
     testChannel.setCommand("true"); 
     testChannel.connect(); 
     if(logger.isDebugEnabled()) { 
      logger.debug("Session erfolgreich getestet, verwende sie erneut"); 
     } 
     testChannel.exit(); 
    } catch (Throwable t) { 
     logger.info("Session kaputt. Baue neue."); 
     session = jsch.getSession(user, host, port); 
     session.setConfig(config); 
     session.connect(); 
    } 
    return session; 
} 

該版本運行幾個星期:最終的解決方案,guarateed unelegant和工作。每天一次,我都會記錄信息消息。

開通頻道和執行一些無所事事命令的成本有點令人討厭,但我沒有發現其他方式明確地確定會話的狀態。

+0

很好的解決方案,只是一個提示:我會添加'testChannel.exit();'成功檢查後,否則你最終會在服務器端爲每個檢查再多一個sftp-server守護進程 – GWu 2014-07-31 07:24:00

+0

謝謝。增加了'testChannel.exit()'。 – blafasel 2014-08-10 12:24:23

+0

我在打開多個頻道時遇到了死鎖問題。使getSession()'synchronized'解決了這個問題,但這有點性能問題。你知道哪部分可能需要同步嗎?也許測試通道connect = disconnect? – 2015-06-15 08:05:32