我正在开发一个Android应用程序

  • 首先,我必须通过TCP套接字
  • 连接到硬件服务器
  • 连接后,我将必须向服务器发送* 99 * 1 ##,然后服务器将以“*#* 1 ## *#* 1 ##”响应
  • 然后,我需要保持此套接字处于 Activity 状态并读取传入消息
  • 至此,服务器可以不时向我发送消息。但是,何时发送消息或消息长度不确定。
  • 每个消息都将以'##'结尾,例如* 1 * 1 * 18 ##,* 1 * 0 * 19 ##,* 1 * 1 *#4 * 11 ##等。
  • 当客户端(此应用程序)收到消息时,它将通知 Activity 以更新UI。

  • 因此,我创建了一个线程子类来执行此操作
    public class ServerThread extends Thread {
        public interface OnReadListener {
            public void onRead(ServerThread serverThread, String response);
        }
    
        Socket socket;
        String address;
        int port;
        OnReadListener listener = null;
    
        public ServerThread(String address, int port) {
            this.address = address;
            this.port = port;
        }
    
        @Override
        public void run() {
            try {
                socket = new Socket(InetAddress.getByName(address), port);
    
                BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                PrintWriter writer = new PrintWriter(bw, true);
                writer.println("*99*1##");
                writer.flush();
    
                BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String line;
    
                while (!socket.isConnected() && !Thread.currentThread().isInterrupted()) {
                    line = br.readLine();
    
                    if (line != null) {
                        Log.i("Dev", "Line ")
    
                        if (listener != null) {
                            listener.onRead(this, line);
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public void setListener(OnReadListener listener) {
            this.listener = listener;
        }
    }
    

    在 Activity 中,我这样做
    public class MainActivity extends Activity {
    
        ServerThread st = null;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main_activity);
        }
    
        @Override
        public void onResume() {
            startMonitoring();
    
            super.onResume();
        }
    
        @Override
        public void onPause() {
            stopMonitoring();
    
            super.onPause();
        }
    
        private void startMonitoring() {
            stopMonitoring();
    
            st = new ServerThread(SERVER_IP_ADDRESS, SERVER_PORT);
            st.setListener(new OnReadListener{
                @Override
                public void onRead(ServerThread serverThread, String response) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            // update UI or do something with response
                        }
                    })
                }
            });
            st.start();
        }
    
        private void stopMonitoring() {
            if (st != null) {
                st.stop();
                st = null;
            }
        }
    }
    

    开始这项 Activity 后,我发现
  • 消息“* 99 * 1 ##”已发送到服务器,我可以从服务器硬件上看到此消息。
  • 但是,我仅从服务器'*#* 1 ## *#* 1 ##'得到响应的第一行
  • 之后,套接字仍然连接(未打印stacktrace),但是我再也没有收到来自服务器的任何消息。侦听器永远不会被调用。

  • 我不知道如何使这项工作。任何建议都欢迎。

    一些注意事项,您可能需要了解

    我并不会确定BufferReader是否是我完成工作所需的正确对象。因为当读取失败时,它将返回null,并且循环将继续运行。我可能需要一些可以冻结线程等待输入的对象。由于服务器可能会在几秒钟,几分钟,几小时或更长时间内发送消息,因此该对象可以一直等待输入。收到消息后,继续执行代码并转到下一轮循环。

    (我是专职iOS开发人员,对Java不太熟悉)

    最终编辑

    仔细检查代码后,我发现自己犯了一个愚蠢的错误
    writer.println("*99*1##")
    

    基本上,println将发送“* 99 * 1 ##”,然后跟着 newline 。但是我的硬件服务器不喜欢这样,所以它终止了连接。这就是为什么我从BufferReader的readLine()中得到null的原因。

    我更改为
    writer.print("*99*1##")
    

    服务器收到“* 99 * 1 ##”并保持连接。然后,我可以像EJP一样再次循环读取响应
    String line;
    while ((line = br.readLine()) != null) {
        if (listener != null) {
            listener.onRead(this, line);
        }
    }
    
    if (listener != null) {
        listener.onTerminated(this);
    }
    

    最佳答案

    while (!socket.isConnected() ...
    

    问题在这里。无论如何,测试是没有意义的,因为它永远不会是错误的,但是否定它意味着受控块将永远不会执行。只需删除isConnected()测试。

    当读取失败时,它将返回null,并且循环将继续运行。

    因为您没有正确处理这种情况。如果line为null,则必须退出循环并关闭连接。通常的写法是:
    String line;
    while ((line = reader.readLine()) != null)
    {
        // ...
    }
    

    您在循环中的睡眠实际上只是在浪费时间。

    07-28 03:16
    查看更多