web-dev-qa-db-fra.com

JSch: Comment maintenir la session en vie

J'écris un programme d'interface graphique Java pour la gestion des routes statiques à l'aide de SSH. Mon code est le suivant:

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

Le problème est que lorsque j'appelle la méthode connect et que j'appelle ensuite addroute, le programme retourne 

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

J'ai essayé d'obtenir le statut de session avec

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

ou 

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

J'ai aussi essayé d'utiliser Keepalive, mais ça ne marche pas non plus.

Mon intention est de créer une session sur l'hôte (connexion), tout en laissant la session ouverte, d'exécuter une ou plusieurs commandes et éventuellement d'exécuter d'autres commandes, puis de fermer la session lorsqu'elle n'est pas nécessaire (déconnexion). J'ai cherché sur ce forum et j'ai trouvé cette question mais le code est créer une méthode pour définir une commande à exécuter en premier, puis créer la session, appeler la méthode de la commande et fermer le session.

Des idées sur la façon de faire comme je l'ai mentionné ci-dessus?

11
user2277956

Après avoir essayé Session.sendKeepAliveMsg() sans succès, je suis arrivé à la solution suivante qui semble être plutôt stable:

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

Mise à jour: Quelques jours plus tard, il a échoué.

J'ai essayé de le tester en tuant la session ouverte sur le serveur. Toutes les versions précédentes que j'avais testées de cette manière affichaient exactement le même comportement, quel que soit le problème apparu après avoir attendu quelques jours ou mis fin au processus du serveur. J'ai donc pensé que ce test - et son résultat pour la solution ci-dessus - avait un sens. Malheureusement ce n'est pas le cas.

Je vais essayer d'autres moyens de résoudre ce problème et de vous tenir au courant.

Mise à jour 2: Solution finale, garantie sans surveillance et opérationnelle:

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

Cette version fonctionne plusieurs semaines dans un environnement productif. Une fois par jour, le message d’information est enregistré.

Les coûts liés à l’ouverture d’une chaîne et à l’exécution d’une commande de type «rien à rien» sont un peu gênants, mais je n’ai trouvé aucun autre moyen d’être absolument sûr de l’état de la session.

14
blafasel

Vous pouvez essayer en appelant la méthode suivante avant d'appeler Session # connect () .

Session # setServerAliveInterval (en millisecondes)

Bien que j'ai trouvé une autre fonction Session # sendKeepAliveMsg () qui peut être essayée.

5
Garry

Vous pouvez utiliser un pool, j’ai utilisé org.Apache.commons.pool2, de sorte que le pool est responsable de la fourniture de sessions connectées, essentiellement:

  • Créer une session JSCH sur makeObject
  • connecter sur activer si déconnecté
  • vérifier si isConnected on validate
  • sendKeepAliveMsg sur Passivate

Ci-dessus a fonctionné pour moi, gardez également à l'esprit que si vous ajoutez une logique à valider, poolConfig doit définir true sur testOnBorrow ou testOnReturn. J'ai donc utiliséKeyedObjectPoolvous devriez obtenez les connexions du pool via la méthodeborrowObjectet assurez-vous de les renvoyer au pool une fois l'opération terminée viareturnObject.

https://commons.Apache.org/proper/commons-pool/api-2.2/org/Apache/commons/pool2/PooledObjectFactory.html

0
Ringuerel