java - 服务内的线程 - 需要等待线程完成 [Android]

标签 java android multithreading

我的应用程序通过 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/

相关文章:

java - 只有一个线程写入时的线程安全

java - 如何在每个线程完成 Java 运行后运行任务?

java - 使用 Spring MVC 的 tomcat 中的 PATCH 方法

java - opencsv导入无法解决

java - 在java中使用扫描器类输入

android - 替代Android中的 "FLAG_BLUR_BEHIND"?

java - 如何通过连接到远程位置来更新 Android 数据库

java - 读取包含多个元素的 XML

android - 如何制作这种类型的可扩展 View

java - 在 Java 中同时处理 Json 数组并按顺序处理