繁体   English   中英

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

[英]Android : Keep socket open to read message from server

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

  • 首先,我必须通过TCP套接字连接到硬件服务器
  • 连接后,我必须将* 99 * 1 ##发送到服务器,然后服务器将响应“*#* 1 ## *#* 1 ##”
  • 然后,我需要保持此套接字活动并读取传入的消息
  • 在此之后,服务器可以不时向我发送消息。 但是,何时发送消息或消息长度未确定。
  • 每条消息都以'##'结尾,例如,* 1 * 1 * 18 ##,* 1 * 0 * 19 ##,* 1 * 1 *#4 * 11 ##等等。
  • 当客户端(此应用程序)收到消息时,它将通知活动更新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;
    }
}

在活动中,我这样做

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;
        }
    }
}

在我开始这项活动后,我发现了这一点

  • 消息“* 99 * 1 ##”已发送到服务器,我可以从服务器硬件看到此消息。
  • 但是,我只得到服务器的第一行响应'*#* 1 ## *#* 1 ##'
  • 之后,socket仍然连接(stacktrace没有打印),但我从来没有从服务器得到任何进一步的消息。 监听器永远不会被调用。

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

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

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

(我是全职的iOS开发人员,不熟悉Java)

最终编辑

在仔细检查代码后,我发现了我犯的愚蠢错误

writer.println("*99*1##")

基本上,println将发送“* 99 * 1 ##”,然后使用换行符 但我的硬件服务器不喜欢它,所以它终止连接。 这就是我从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)
{
    // ...
}

你在你的循环中睡觉只是浪费时间。

尝试这个

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/

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM