20

我正在尝试从这个简单的例子中做一些事情:

SSH,用安卓执行远程命令

我只是想看看我是否可以使用 SSH 从我的 android 手机连接到 linux 服务器,但它不起作用......

这是我的主要代码:

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

我做错什么了 ?我没有错误消息,并且在我的 Linux 上看不到任何 SSH 连接。我添加了库 jsch 和 jzlib。我可以毫无问题地连接腻子会话。

EDIT1:事实上,我发现了一个错误,它解释了为什么即使我不知道如何解决问题它也不起作用。错误是:

android.os.NetworkOnMainThreadException

所以这似乎意味着该应用程序无法在其主线程上执行网络操作......

4

3 回答 3

23

您必须在另一个线程中执行该代码,这样您就不会挂起 UI 线程,这就是该异常的含义。如果 UI 线程正在执行网络调用,则它无法重新绘制 UI,因此您的用户会在应用程序等待网络调用完成时看到不响应他们的冻结 UI。Android 想要避免这样的不良用户体验,所以它会通过抛出这个异常来阻止你做这样的事情。

您的 onCreate() 方法应该调用另一个线程(我建议在原始线程上使用 AsyncTask)来执行 SSH 连接。然后,当它完成后,它可以将结果发布回 UI 线程,并从 UI 线程安全地更新应用程序的 UI。

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

于 2013-01-14T19:03:59.320 回答
18

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();
}
于 2014-11-02T18:38:46.660 回答
8

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'
}
于 2018-02-08T02:47:26.600 回答