Ausgabe eines SSH-Kommandos auslesen

  • 8 Antworten
  • Letztes Antwortdatum
M

maksimilian

Ambitioniertes Mitglied
0
Hallo Ihr,
ich schicke in einer App via SSH ein Shell-Kommando an einen Pi, was auch funktioniert. Mir gelingt es nur nicht, die vom Kommando erzeugte Ausgabe auszulesen. Mein Code sieht folgendermaßen aus:
Code:
public String ssh_command = "ps -elf"; 
public class MyThread implements Runnable {
    @Override
    public void run() {
        try {
            JSch jsch = new JSch();
            //
            byte[] buffer = new byte[1024];
            ArrayList lines = new ArrayList<>();
            //
            Session session = jsch.getSession(User, IP, Port); // Port = 22
            session.setPassword(Pass);
            Properties prop = new Properties();
            prop.put("StrictHostKeyChecking", "no");
            session.setConfig(prop);
            //
            session.connect();
            //
            ChannelExec channelssh = (ChannelExec) session.openChannel("exec");
            channelssh.setCommand(ssh_command);
            channelssh.connect();
        //
        // Ausgaben der Konsole auslesen.
            InputStream in = channelssh.getInputStream();
            String line = "";
            while (true) {
                while (in.available() > 0) {
                    int i = in.read(buffer, 0, 1024);
                    // wenn Ausgabe leer
                    if (i < 0) {
                        break;
                    }
                    line = new String(buffer, 0, i);
                    channelssh.setCommand(ssh_command);
                    lines.add(line);
                }
                // Wir wurden ausgeloggt.
                if (line.contains("logout")) {
                    break;
                }
                // Befehl beendet oder Verbindung abgebrochen.
                if (channelssh.isClosed()) {
                    break;
                }
                // Warte einen kleinen Augenblick mit der nächsten Zeile.
                try {
                    Thread.sleep(1000);
                } catch (Exception ee) {
                    Log.d(LOGTAG,  "Exception ee=" + ee);
                }
            }
            //
            channelssh.disconnect();
            session.disconnect();
            Log.d(LOGTAG, "lines=" + lines);
        }catch (Exception e){
            Log.d(LOGTAG,  "Exception e=" + e);
        }
    } // run
} // MyThread

lines ist immer leer. Was mache ich falsch ?

maksimilian
 
Hallo erstelle mal den Inputsream vor dem Connect.

das mit deiner Klasse wird so auch nicht gehn.
public class MyThread extends Thread {

dann ist es auch ein Thread und wird mit Start auch so ausgeführt.
new MyThread().start();
 
Zuletzt bearbeitet:
Also, wenn ich einen Thread formuliere, darf angenommen werden, dass der von mir auch gestartet wird (ich hatte ja erwähnt, dass SSH funktioniert)!
Zur Auswertung der SSH-Ausgabe: Ich gebe zu, dass der Code nicht auf meinem Mist gewachsen ist und ich ihn evtl. nicht ausreichend hinterfragt habe. Was funktioniert ist:
Code:
.....
 String outputBuffer = "";
 channelssh.setCommand(ssh_command);
 channelssh.connect();
 InputStream input = channelssh.getInputStream();
 int data = input.read();
 while(data != -1) {
     outputBuffer += ((char)data);
     data = input.read();
 }
  Log.d(LOGTAG, " outputBuffer="+ outputBuffer);
 channelssh.disconnect();
 session.disconnect();

Nun reicht das aber nicht, weil ich sowohl stdout als auch stderr auslesen möchte und habe dazu folgende Programmierung gefunden:
Code:
channelssh.setCommand(ssh_command);
channelssh.connect();
InputStream input = channelssh.getInputStream();
InputStream err = channelssh.getExtInputStream();
byte[] tmp = new byte[1024];
StringBuilder stdoutBuffer = new StringBuilder();
StringBuilder stderrBuffer = new StringBuilder();

while (true) {
    while (input.available() > 0) {
        int i = input.read(tmp, 0, 1024);
        if (i < 0) break;
        stdoutBuffer.append(new String(tmp, 0, i));
    }
    while (err.available() > 0) {
        int i = err.read(tmp, 0, 1024);
        if (i < 0) break;
        stderrBuffer.append(new String(tmp, 0, i));
    }
    if (channelssh.isClosed()) {
        if ((input.available() > 0) || (err.available() > 0)) continue;
        System.out.println("exit-status: " + channelssh.getExitStatus());
        break;
    }
    try {
        Thread.sleep(1000);
    } catch (Exception ee) {
    }
}
Log.d(LOGTAG, " stdoutBuffer="+ stdoutBuffer.toString());
Log.d(LOGTAG, " stderrBuffer="+ stderrBuffer.toString());

Leider funktioniert das nicht. Beide Buffer sind leer. Im ersten Beispiel funktioniert die read-Methode im zweiten nicht.
 
Ich habe deinen ersten Code getestet.
Ging erstmals nicht bekam die Fehlermeldung das es nicht im einen Thread ausgeführt wird.
Ist auch nicht verwunderlich wenn man zb. die Run Methote direckt aufruft. dann ist es kein Thread.
Mit meiner Änderung extends Thread (erben von Thread ohne Runnable) und richtigen Aufruf des Threads läuft es.

Also, wenn ich einen Thread formuliere, darf angenommen werden, dass der von mir auch gestartet wird
Start ja aber wie? Wirklich als Thread?
Tipp das was du formuliert hast ist noch lange kein Thread wird es erst durch den richtigen Start den du uns nicht zeigst.
Wenn du es nicht glaubst setze einen BrakPoint in den Catch Zweig.

So und nun zeige wie du deinen Klasse in der Activity startest.



Der Aufruf deiner Klasse sollte in etwa so aussehen.
Code:
 Thread thread = new Thread(new MyThread());
        thread.start();

machst du es so wird er auch laufen. Ich bevorzuge die erste Version.
 
Zuletzt bearbeitet:
PS auch deine neuen Varianten würden laufen wenn sie in einen Thread ausgeführt werden.
 
jogimuc schrieb:
Der Aufruf deiner Klasse sollte in etwa so aussehen.
Code:
 Thread thread = new Thread(new MyThread());
        thread.start();
Sieht bei mir genau so aus. Entschuldige, wenn ich mich unvollständig äußere. Ich setze manches voraus, was Du nicht wissen kannst. Und ich versuche, hier so wenig Code wie möglich zu posten, um die Zumutung für den Leser, sich das alles anzuschauen, möglichst gering zu halten.
Die zweite Lösung, welche bei mir nicht funktioniert, läuft genauso wie die erste im gleichen Thread.
Übrigens, danke, dass Du Dir wieder so viel Mühe mit mir machst !
 
Habe aber keine pi, Verbindung mit einen Linux Rechner. Und echten Handy nicht Emulator.

ich würde sagen das ist ein zeitliches problem und zwar ist der Inputstream noch nicht gefüllt die Daten wurden also zum zeitpunkt
if (channelssh.isClosed())
noch nicht übertragen. Da hilft dir auch nicht das warten am ende.



Mit deinen füllen des Buffers bin ich nicht ganz einverstanden, schaue dir doch mal an wie Prozess Ausgabe aufgebaut ist. Das sind Zielen mit einen Cr "\n".
int i = in.read(buffer, 0, 1024);
Du liest immer genau 1024 Zeichen aus dem Streame in einen Buffer. Du musst schon Zeilen weise arbeiten.

line = new String(buffer, 0, i);
if (line.contains("logout"))
Da kann es passieren das das Wort "Logout" nach dem du in einer Zeile suchst auf zwei Zeilen verteilt ist und somit nicht erkannt wird.
 
Zuletzt bearbeitet:
Danke auch für diese Hinweise. Ich gehe manchmal bei der Implementierung neuer Funktionen pragmatisch vor, kopiere Tipps aus dem Internet und modifiziere dann , wenn sie funktionieren.

Was die stderr Ausgabe betrifft, behelfe ich mich mit der Umleitung von stderr auf stdout.
 
Code:
 channelssh.setCommand(ssh_command);
                InputStream in = channelssh.getInputStream();
                channelssh.connect();

                String line = "";
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in));

                while (true) {
                        line = bufferedReader.readLine();
                        lines.add(line+"\n");

                    // Wir wurden ausgeloggt.
                    if (line.contains("logout")) {
                        break;
                    }
                    // Befehl beendet oder Verbindung abgebrochen.
                    if (!bufferedReader.ready()) {
                        break;
                    }

                }
                //
                channelssh.disconnect();
                session.disconnect();
                Log.d(LOGTAG, "lines=" + lines);

            }catch (Exception e){
                Log.d(LOGTAG,  "Exception e=" + e);
            }

Code:
while ((line = bufferedReader.readLine()) !=null) {
                    lines.add(line+"\n");

                    // Wir wurden ausgeloggt.
                    if (line.contains("logout")) {
                        break;
                    }
                }

PS. if (channelssh.isClosed())
wird dir immer dazwischen funken denn die Daten kommen ja nur langsam an. Nach einiger Zeit wird das Ture und deine Auswertung ist noch nicht beendet aber wird hierdurch abgebrochen.

du musst das immer etwas zeitlicher sehen oder zeitlicher Parallel denken.
Sind zwar nur mikro-- oder nano Sekunden ist aber so.
 
Zuletzt bearbeitet:

Ähnliche Themen

H
Antworten
2
Aufrufe
1.682
Hcman
H
M
  • maksimilian
Antworten
6
Aufrufe
1.080
jogimuc
J
M
  • maksimilian
Antworten
1
Aufrufe
1.579
jogimuc
J
Zurück
Oben Unten