2013-04-21 17 views
10

Sto scrivendo un programma Java GUI per la gestione statica dei percorsi tramite SSH. Il mio codice è il seguente:JSch: Come mantenere viva la sessione in su

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); 
     } 
    } 
}  

Il problema è quando chiamo il metodo di connessione e quindi chiamando l'addroute, il programma ritorna

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

Ho cercato di ottenere lo stato di sessione sia con

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

o

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

Ho anche provato a usare keepalive, ma non funziona neanche.

La mia intenzione è quella di creare una sessione per ospitare (accedere), lasciando la sessione in su, eseguire un comando o comandi e magari eseguire altri comandi in seguito, quindi chiudere la sessione quando non è necessaria (scollegarsi). Ho cercato su questo forum e ho trovato questo question ma il codice è creare un metodo per definire un comando da eseguire prima, e quindi creare la sessione, chiamare il metodo del comando e chiudere la sessione.

Qualche idea su come fare come ho menzionato sopra?

risposta

10

Dopo aver provato Session.sendKeepAliveMsg() senza successo, sono arrivato alla soluzione seguente, che sembra essere piuttosto stabile:

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; 
} 

Aggiornamento: Qualche giorno dopo non è riuscito.

Ho provato a testarlo uccidendo la sessione aperta sul server. Tutte le versioni precedenti che ho testato in questo modo hanno mostrato lo stesso identico comportamento, indipendentemente dal fatto che il problema si sia verificato dopo aver atteso alcuni giorni o aver ucciso il processo del server, quindi ho pensato che questo test - e il suo risultato per la soluzione di cui sopra - fosse significativo. Sfortunatamente non lo è.

Ho intenzione di provare altri modi per risolverlo e tenerti aggiornato.

Aggiornamento 2: Soluzione finale, Guarateed unelegant e di lavoro:

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; 
} 

Questa versione viene eseguito diverse settimane in un ambiente produttivo. Una volta al giorno ho registrato il messaggio informativo.

I costi di apertura di un canale e l'esecuzione di alcuni comandi do-nothing sono alquanto fastidiosi, ma non ho trovato altro modo per essere definitivamente sicuro dello stato della sessione.

+0

bella soluzione, un solo suggerimento: aggiungerei 'testChannel.exit();' dopo aver controllato con successo, altrimenti si finisce con un altro processo daemon sftp-server sul lato sever per ciascun controllo. – GWu

+0

Grazie.Aggiunto 'testChannel.exit()'. – blafasel

+0

Ho avuto problemi di deadlock durante l'apertura di più canali. Rendere getSession() 'sincronizzato 'ha risolto questo, ma è un po' un colpo di prestazioni. Sai quale parte potrebbe essere necessario sincronizzare? Forse il canale di prova connect = disconnect? –