2013-01-14 7 views
13

Ich versuche, etwas von diesem einfachen Beispiel zu machen:Einfache SSH Verbindung mit JSch

SSH, execute remote commands with Android

Ich will nur sehen, wenn ich von meinem Android-Handy auf einem Linux-Server mit SSH eine Verbindung herstellen können, aber es doesn ‚t Arbeit ...

Hier ist mein Haupt-Code:

package com.example.ssh; 

import java.util.Properties; 
import com.jcraft.jsch.JSch; 
import com.jcraft.jsch.Session; 
import android.os.Bundle; 
import android.app.Activity; 

public class MainActivity extends Activity { 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 

    try 
    { 
     JSch jsch = new JSch(); 
      Session session = jsch.getSession("root","192.168.0.26", 22); 
      session.setPassword("xxxxx"); 

      // Avoid asking for key confirmation 
      Properties prop = new Properties(); 
      prop.put("StrictHostKeyChecking", "no"); 
      session.setConfig(prop); 

      session.connect(); 

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

Was habe ich falsch gemacht? Ich habe keine Fehlermeldungen und ich sehe keine SSH-Verbindung auf meinem Linux. Ich habe die Bibliotheken jsch und jzlib hinzugefügt. Ich habe kein Problem mit einer Putty-Session zu verbinden.

EDIT1: Tatsächlich fand ich einen Fehler, der erklärt, warum es nicht funktioniert, selbst wenn ich nicht weiß, wie man das Problem löst. Der Fehler ist:

android.os.NetworkOnMainThreadException

so scheint es, zu verstehen, dass der App nicht einen Netzwerkbetrieb auf seinem Haupt-Thread ausführen kann ...

Antwort

16

Sie haben diesen Code auszuführen, in ein anderer Thread, so dass Sie nicht den UI-Thread hängen, ist was diese Ausnahme bedeutet. Wenn der UI-Thread einen Netzwerkaufruf ausführt, kann er die Benutzeroberfläche nicht neu erstellen, sodass Ihre Benutzer eine eingefrorene Benutzeroberfläche sehen, die nicht darauf reagiert, während die App auf den Netzwerkaufruf wartet, um den Vorgang abzuschließen. Android möchte so schlechte Benutzererfahrungen vermeiden, dass es verhindert, dass Sie solche Dinge tun, indem Sie diese Ausnahme auslösen.

Ihre onCreate() - Methode sollte einen anderen Thread aufrufen (ich würde vorschlagen, eine AsyncTask über einen Raw-Thread zu verwenden), um die SSH-Verbindung durchzuführen. Anschließend können Sie die Ergebnisse wieder im UI-Thread veröffentlichen und die Benutzeroberfläche der Anwendung vom UI-Thread aus sicher aktualisieren.

http://developer.android.com/reference/android/os/AsyncTask.html

+0

Vielen Dank ! Ich werde deine Lösung versuchen. – Pozinux

12

chubbsondubs Lösung ist perfekt. Ich will nur den Code teilen, die ich für dieses Problem für die Menschen zu gemacht, die eine schnelle Lösung wollen:

public class MainActivity extends Activity { 
@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 
    new AsyncTask<Integer, Void, Void>(){ 
     @Override 
     protected Void doInBackground(Integer... params) { 
      try { 
       executeRemoteCommand("root", "myPW","192.168.0.26", 22); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
      return null; 
     } 
    }.execute(1); 
} 

public static String executeRemoteCommand(String username,String password,String hostname,int port) 
     throws Exception { 
    JSch jsch = new JSch(); 
    Session session = jsch.getSession(username, hostname, port); 
    session.setPassword(password); 

    // Avoid asking for key confirmation 
    Properties prop = new Properties(); 
    prop.put("StrictHostKeyChecking", "no"); 
    session.setConfig(prop); 

    session.connect(); 

    // SSH Channel 
    ChannelExec channelssh = (ChannelExec) 
      session.openChannel("exec"); 
    ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
    channelssh.setOutputStream(baos); 

    // Execute command 
    channelssh.setCommand("lsusb > /home/pi/test.txt"); 
    channelssh.connect(); 
    channelssh.disconnect(); 

    return baos.toString(); 
} 
0

A Kotlin Lösung:

import android.os.AsyncTask 
import android.os.Bundle 
import android.support.v7.app.AppCompatActivity 
import com.jcraft.jsch.ChannelExec 
import com.jcraft.jsch.JSch 
import java.io.ByteArrayOutputStream 
import java.util.* 

class MainActivity : AppCompatActivity() { 
    override fun onCreate(savedInstanceState: Bundle?) { 
     super.onCreate(savedInstanceState) 
     setContentView(R.layout.activity_main) 
     SshTask().execute() 
    } 

    class SshTask : AsyncTask<Void, Void, String>() { 
     override fun doInBackground(vararg p0: Void?): String { 
      val output = executeRemoteCommand("demo", "password", "test.rebex.net") 
      print(output) 
      return output 
     } 
    } 
} 

fun executeRemoteCommand(username: String, 
         password: String, 
         hostname: String, 
         port: Int = 22): String { 
    val jsch = JSch() 
    val session = jsch.getSession(username, hostname, port) 
    session.setPassword(password) 

    // Avoid asking for key confirmation. 
    val properties = Properties() 
    properties.put("StrictHostKeyChecking", "no") 
    session.setConfig(properties) 

    session.connect() 

    // Create SSH Channel. 
    val sshChannel = session.openChannel("exec") as ChannelExec 
    val outputStream = ByteArrayOutputStream() 
    sshChannel.outputStream = outputStream 

    // Execute command. 
    sshChannel.setCommand("ls") 
    sshChannel.connect() 

    // Sleep needed in order to wait long enough to get result back. 
    Thread.sleep(1_000) 
    sshChannel.disconnect() 

    session.disconnect() 

    return outputStream.toString() 
} 

In build.gradle add:

dependencies { 
    ... 
    compile group: 'com.jcraft', name: 'jsch', version: '0.1.54' 
}