Простой SSH подключается к JSch

Я пытаюсь сделать что-то из этого простого примера:

SSH, выполните удаленные команды с Android

Я просто хочу посмотреть, могу ли я подключиться с моего телефона Android к серверу linux с помощью SSH, но он не работает...

Вот мой основной код:

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

Что я сделал неправильно? У меня нет сообщений об ошибках, и я не вижу никакого SSH-подключения на моем Linux. Я добавил библиотеки jsch и jzlib. У меня нет проблем с подключением к сеансу шпаклевки.

EDIT1: На самом деле я обнаружил ошибку, объясняющую, почему она не работает, даже если я не знаю, как решить проблему. Ошибка:

android.os.NetworkOnMainThreadException

так что это означает, что приложение не может выполнить сетевую операцию в своем основном потоке...

Ответ 1

Вы должны выполнить этот код в другом потоке, чтобы не повредить поток пользовательского интерфейса, что это означает это исключение. Если поток пользовательского интерфейса выполняет сетевой вызов, он не может перерисовывать интерфейс, чтобы ваши пользователи видели замороженный пользовательский интерфейс, который не отвечает на них, пока приложение ожидает завершения сетевого вызова. Android хочет избежать подобных неприятностей, так что это мешает вам делать такие вещи, выбрасывая это исключение.

Ваш метод onCreate() должен вызывать другой поток (я бы предложил использовать AsyncTask поверх необработанного потока) для выполнения SSH-соединения. Затем, когда это будет сделано, он сможет опубликовать результаты обратно в поток пользовательского интерфейса и безопасно обновить пользовательский интерфейс приложения из потока пользовательского интерфейса.

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

Ответ 2

Решение

chubbsondubs идеально. Я просто хочу поделиться кодом, который я сделал для этой проблемы, также для людей, которые хотят быстрое решение:

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

Ответ 3

A Kotlin решение:

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

В build.gradle добавить:

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