我试图通过这个简单的例子来创造一些东西:
SSH, execute remote commands with Android
我只是想看看我是否可以使用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。我没有问题与putty会话联系。
EDIT1:事实上,我发现了一个错误,解释了为什么即使我不知道如何解决问题它也不起作用。错误是:
android.os.NetworkOnMainThreadException
所以它似乎意味着应用程序无法在其主线程上执行网络操作......
答案 0 :(得分:17)
您必须在另一个线程中执行该代码,这样您就不会挂起UI线程就是该异常的含义。如果UI线程正在执行网络调用,则无法重新绘制UI,因此当应用程序等待网络调用完成时,您的用户会看到一个冻结的UI,该UI不响应它们。 Android希望避免像这样糟糕的用户体验,因此它会阻止您通过抛出此异常来执行此类操作。
你的onCreate()方法应该调用另一个线程(我建议在原始线程上使用AsyncTask)来执行SSH连接。然后,当它完成后,它可以将结果发布回UI线程,并从UI线程安全地更新应用程序的UI。
http://developer.android.com/reference/android/os/AsyncTask.html
答案 1 :(得分:15)
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();
}
答案 2 :(得分:1)
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'
}