我的应用程序通过 SSH 连接到服务器(使用 JSch),但如果我发送命令而不等待结果返回,应用程序将无法跟上,并且在不等待而发送下一个命令时它会错过回复。
我尝试过一些方法,例如使用对象来同步线程并使用wait()和notify(),但UI线程在执行此操作时保持卡住状态。 thread.join() 可以工作,但会导致运行速度非常慢,因为它在命令之间卡住。
长话短说,我需要等待服务器的回复,处理它并绘制它,然后发送下一个命令。
非常感谢任何帮助,因为这是针对我的计算项目的。 :D
//A snippet of my service procedure that handles the SSH connections
public String sendCommand(final String command) {
Finished = false;
final Thread sshServiceThread = new Thread(new Runnable() {
String sshPassword = null;
private volatile boolean running = true;
@Override
public void run () {
while (running) {
try {
session = jSch.getSession(username, host, port);
checkPassword();
session.setPassword(sshPassword);
session.setConfig("StrictHostKeyChecking", "no");
//TODO - REMOVE THIS
Log.w("DEBUG", "Host: " + host + " Username: " + username + " Password: " + password);
Log.w("Security", "REMOVE THIS BEFORE RELEASE");
session.connect();
channel = session.openChannel("shell");
DataOutputStream dataOut = new DataOutputStream(channel.getOutputStream());
InputStream in = channel.getInputStream();
channel.connect();
//Send command
Log.w("Command", "Command: " + command);
dataOut.writeBytes(command + " && echo TheCommandWasFinished" + "\r\n");
dataOut.flush();
byte[] tmp = new byte[1024];
String replyLine = "";
try {
while (true) {
while (in.available() > 0) {
int i = in.read(tmp, 0, 1024);
if (i < 0)
break;
String lastLine = replyLine;
replyLine = (new String(tmp, 0, i));
if (!replyLine.contains("&& echo TheCommandWasFinished")) {
if (replyLine.contains("TheCommandWasFinished")) {
String result = lastLine;
Log.w("Result", result);
reply = result;
synchronized (syncObject) {
notify();
}
return;
}
}
}
}
} catch (Exception exception) {
Log.w("Exception", exception);
}
} catch (JSchException jschX) {
Log.w("Exception", jschX);
if (jschX.toString().contains("timeout")) {
Log.w("Error", "IP Address is incorrect");
Toast.makeText(getApplicationContext(), "Cannot connect to host, Check IP and connection.", Toast.LENGTH_LONG).show();
}
if (jschX.toString().contains("Auth fail")) {
Log.w("Error", "Username/Password Incorrect");
Toast.makeText(getApplicationContext(), "Username/Password Incorrect", Toast.LENGTH_LONG).show();
}
if (jschX.toString().contains("ECONNRESET")) {
Toast.makeText(getApplicationContext(), "Connection failure", Toast.LENGTH_LONG).show();
}
} catch (IOException Exception) {
Log.w("Exception", Exception);
}
}
}
void checkPassword() {
Log.w("Password set", "Password: " + sshService.password);
sshPassword = sshService.password;
}
});
sshServiceThread.start();
try {
synchronized(syncObject) {
syncObject.wait(3000);
}
}
catch (Exception Exception) {
Log.w("Exception", Exception);
}
Finished = true;
return reply;
}
// Last few lines of my Logcat
02-12 00:11:10.281 32701-32701/com.lonedev.slypanel W/Values﹕ Host: 192.168.0.14 Username: adam
02-12 00:11:10.282 32701-32701/com.lonedev.slypanel W/Save﹕ Saved 192.168.0.14 adam
02-12 00:11:10.354 32701-32701/com.lonedev.slypanel W/Host:﹕ 192.168.0.14
02-12 00:11:10.355 32701-32701/com.lonedev.slypanel W/Host:﹕ 192.168.0.14
02-12 00:11:13.398 32701-684/com.lonedev.slypanel W/Password set﹕ Password: **********
02-12 00:11:13.399 32701-684/com.lonedev.slypanel W/DEBUG﹕ Host: 192.168.0.14 Username: adam Password: **********
02-12 00:11:13.399 32701-684/com.lonedev.slypanel W/Security﹕ REMOVE THIS BEFORE RELEASE
02-12 00:11:13.794 32701-684/com.lonedev.slypanel W/Command﹕ Command: top -b -n2 | grep "Cpu(s)" | awk '{print $2 + $4}' | tail -1
// This should return a value for cpu usage e.g. 37.5
// UI Freezes here
我读到我可以在这里使用 AsyncTask 而不是线程...但不确定我是否可以在服务内部执行此操作...:P
最佳答案
参见#sending-commands-to-server-via-jsch-shell-channel
... if you are not sure how many lines to read and thus want to use "while", make sure you do something inside while to prevent 1) busy-waiting 2) ending-condition. Example:
while(!end)
{
consoleOutput.mark(32);
if (consoleOutput.read()==0x03) end = true;//End of Text
else
{
consoleOutput.reset();
consoleOutput.readLine();
end = false;
}
}
要处理来自其他线程的输入输出,您可以使用 #non-blocking-buffer
查看jsch examples .
此外,作为设计建议,您可以使用 UserInfo用于传递凭据的接口(interface),而不是直接从 UI 对象传递。
与您的类似项目(基于网络,不是 Android):https://github.com/kohsuke/ajaxterm4j
关于java - 服务内的线程 - 需要等待线程完成 [Android],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28467306/