2013-01-14 21 views
13

Staram się zrobić coś z tym prostym przykładzie:Proste SSH połączyć z jsch

SSH, execute remote commands with Android

Chcę tylko zobaczyć, czy mogę połączyć się z mojego telefonu z systemem Android na serwerze Linux za pomocą protokołu SSH, ale to nie robi „t pracy ...

Tu jest mój główny kod:

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

Co zrobiłem źle? Nie mam komunikatów o błędach i nie widzę żadnego połączenia SSH na moim Linux-ie. Dodałem biblioteki jsch i jzlib. Nie mam problemu z nawiązaniem połączenia z sesją kitową.

EDIT1: W rzeczywistości znalazłem błąd, który wyjaśnia, dlaczego nie działa, nawet jeśli nie wiem, jak rozwiązać problem. Błąd jest:

android.os.NetworkOnMainThreadException

więc wydaje się, że oznacza to, że aplikacja nie może przeprowadzić operację tworzenia sieci na jej głównego wątku ...

Odpowiedz

16

Trzeba wykonać ten kod w inny wątek, więc nie powiesisz wątku UI, co oznacza ten wyjątek. Jeśli wątek interfejsu użytkownika wykonuje połączenie sieciowe, nie może odświeżyć interfejsu użytkownika, aby użytkownicy widzieli zablokowany interfejs użytkownika, który nie reaguje na nie, gdy aplikacja oczekuje na zakończenie połączenia sieciowego. Android chce uniknąć takich nieoczekiwanych wrażeń, aby zapobiec takim operacjom, rzucając ten wyjątek.

Twoja metoda onCreate() powinna wywołać inny wątek (sugerowałbym użycie AsyncTask przez surowy wątek) do wykonania połączenia SSH. Następnie, gdy to zrobi, może opublikować wyniki z powrotem do wątku interfejsu użytkownika i bezpiecznie zaktualizować interfejs użytkownika aplikacji z wątku interfejsu użytkownika. Rozwiązanie

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

+0

Dzięki ! Zamierzam wypróbować Twoje rozwiązanie. – Pozinux

12

chubbsondubs jest doskonały. Ja po prostu chcesz podzielić się kod, który zrobiłem dla tego problemu zbyt dla ludzi, którzy chcą szybkiego rozwiązania:

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

Kotlin rozwiązanie:

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

W build.gradle dodają:

dependencies { 
    ... 
    compile group: 'com.jcraft', name: 'jsch', version: '0.1.54' 
} 
Powiązane problemy