Android : 保持套接字打开以从服务器读取消息

Android : Keep socket open to read message from server

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

因此,我创建了一个线程子类来执行此操作

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后,我发现

我不知道该怎么做。欢迎任何建议。

一些您可能需要知道的注意事项

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

(我是全职iOS Dev,不太熟悉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 (isRunning) {
            line = br.readLine();

            if (line != null) {
                Log.i("Dev", "Line ")

                if (listener != null) {
                    listener.onRead(this, line);
                }
            }
        }

注意:isRunning 是一个布尔变量,用于控制您的线程生命周期。每当您想停止此线程时,请设置 isRunning = false 并在您的连接上调用 close()

如果您想创建一个 TCP 服务器,您应该使用 ServerSocket 而不是 Socket。这是关于 socket 的 java 文档,但 android 使用相同的 http://docs.oracle.com/javase/tutorial/networking/sockets/

while (!socket.isConnected() ...

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

when it failed to read, it will return null and the loop will keep running.

因为你没有正确处理那个案例。如果 line 为空,则必须退出循环并关闭连接。通常的写法是:

String line;
while ((line = reader.readLine()) != null)
{
    // ...
}

你在循环中的睡眠简直就是浪费时间。