Android中使用BufferedReader.readline阻塞读取不到数据,但是ready返回true

Posted 飞剑的博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android中使用BufferedReader.readline阻塞读取不到数据,但是ready返回true相关的知识,希望对你有一定的参考价值。

通过socket测试工具在电脑上发送消息,android真机可以收到响应BufferedReader.ready()返回true,但是readline却一直阻塞。

原因:readline()只有在遇到换行符的时候才会结束,因为发消息的时候加一个换行符即可。

测试工具下载地址:http://files.cnblogs.com/files/feijian/SocketTool.rar

 

附上我的socket客户端代码:

public class QpushClient implements Runnable {
    protected static QpushClient mInstance;
    protected Handler mHandler;
    protected InetSocketAddress mAddress;
    protected String TAG = "QpushClient";
    private final int TIME_OUT = 5 * 1000;
    //巡检周期
    private final int CHECK_PERIOD = 2 * 1000;
    //连接尝试间隔时间
    private final int CONNECT_PERIOD = 30 * 1000;
    private final int HEARTBEART_PERIOD = 10 * 1000;
    //若连接失败或响应失败,则尝试次数为9,若仍无效,则不再尝试
    private final int CONNECT_TRY_TIMES = 9;

    //连接尝试次数
    private int mConnectCount;

    Socket mClientSocket;
    String mHost;
    int mPort;
    //设置是否去读取数据
    boolean isStartRecieveMsg = false;
    //开启心跳检测
    boolean isKeepHeartBeat = false;

    private QpushClient(Handler handler) {
        mHandler = handler;
    }

    public static QpushClient getInstance(Handler handler) {
        if (mInstance == null) {
            mInstance = new QpushClient(handler);
        }
        return mInstance;
    }

    public void init(String host, int port) {
        mHost = host;
        mPort = port;
        new Thread(this).start();
        isStartRecieveMsg = true;
        isKeepHeartBeat = true;
    }

    @Override
    public void run() {
        mAddress = new InetSocketAddress(mHost, mPort);
        if (mClientSocket == null) {
            mClientSocket = new Socket();
        }

        //尝试连接,若未连接,则设置尝试次数
        while (!mClientSocket.isConnected() && mConnectCount < CONNECT_TRY_TIMES) {
            connect();
            if (!mClientSocket.isConnected()) {
                mConnectCount++;
                sleep(CONNECT_PERIOD);
            } else {
                mConnectCount = 0;//连接上,则恢复置0
            }
        }
        if (mClientSocket.isConnected()) {
            //开始登陆
            sendMsg("login");
            recvMsg();
            keepHeartBeat();
        }
    }

    private void connect() {
        try {
            mClientSocket.connect(mAddress);
        } catch (IOException e) {
            e.printStackTrace();
            Log.e(TAG, "mClientSocket.connect fail " + e.getMessage());
        }
    }

    /**
     * 心跳维护
     */
    private void keepHeartBeat() {
        //设置心跳频率,启动心跳
        while(isKeepHeartBeat){
            sendMsg("我是心跳包");
            sleep(HEARTBEART_PERIOD);
        }
    }

    BufferedWriter mWriter;
    BufferedReader mReader;

    /**
     * 不断的检测是否有服务器推送的数据过来
     */
    public void recvMsg() {
        while (mClientSocket != null && mClientSocket.isConnected() && !mClientSocket.isClosed()) {
            try {
                mReader = new BufferedReader(new InputStreamReader(mClientSocket.getInputStream(), "utf-8"));
                while (isStartRecieveMsg) {
                    Log.e(TAG, "recvMsg5");
                    if (mReader.ready()) {
                        Log.e(TAG, "recvMsg6");
                            /*读取一行字符串,读取的内容来自于客户机
                            reader.readLine()方法是一个阻塞方法,
                            从调用这个方法开始,该线程会一直处于阻塞状态,
                            直到接收到新的消息,代码才会往下走*/
                        String data = mReader.readLine();
                        Log.e(TAG,"isStartRecieveMsg data="+data);
                        //handler发送消息,在handleMessage()方法中接收
                        handlerMsg(data);
                    }
                    Thread.sleep(200);
                }
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            sleep(200);
        }
        if (!mClientSocket.isConnected()) {
            connect();
            recvMsg();
        }
        sleep(CHECK_PERIOD);
    }

    private void sleep(long sleepTime) {
        try {
            Thread.sleep(sleepTime);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 销毁socket
     */
    public void onDestory() {
        if (mClientSocket != null) {
            try {
                mClientSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            mClientSocket = null;
        }
    }
    public void sendMsg(String message) {
        PrintWriter writer;
        try {
            writer = new PrintWriter(new OutputStreamWriter(
                    mClientSocket.getOutputStream()), true);
            writer.println(message);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /*
     * Ready for use.
     */
    public void close() {
        try {
            if (mClientSocket != null && !mClientSocket.isClosed())
                mClientSocket.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * 处理服务器返回过来的消息
     * @param data
     */
    private void handlerMsg(String data){
        //对数据进行protobuf解析

        //消息类型:1=登录成功、2=心跳检测、3=推送消息
        int msgType=1;
        switch(msgType){
            case 1:
                sendMsg("success");
                break;
            case 2:
                sendMsg("success");
                break;
            case 3: //需要通知service
                sendMsg("success");
                mHandler.obtainMessage(QpushService.PUSH_TYPE_DATA, data).sendToTarget();
                break;

        }
    }
}

 

以上是关于Android中使用BufferedReader.readline阻塞读取不到数据,但是ready返回true的主要内容,如果未能解决你的问题,请参考以下文章

从 InputStream 读取时,Android Socket BufferedReader readLine() 不起作用

bufferedReader() 在 Kotlin 中究竟是如何工作的?

使用contentResolver将docx转换为Base64会在Android上提供不可读的格式

URL 的 bufferedReader 抛出 IOException

在 Kotlin 中使用 BufferedReader 的最佳方式

BufferedReader BufferedWriter