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

时间:2015-01-27 05:54:56

标签: java android multithreading sockets tcp

我正在使用

的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 ##'
  • 之后,套接字仍然连接(堆栈跟踪未打印),但我从未收到任何来自服务器的消息。听众永远不会被召唤。

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

您可能需要了解

我不能确定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);
}

2 个答案:

答案 0 :(得分:2)

while (!socket.isConnected() ...

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

  

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

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

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

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

答案 1 :(得分:0)

试试这个

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/