蓝牙通信之保证数据的完整性

来源:互联网 发布:天行健君电子商务软件 编辑:程序博客网 时间:2024/05/22 14:18

由来

之前写过一篇Android蓝牙通信的文章,介绍了Android蓝牙的使用和一款蓝牙聊天app的原理,可以点这里看这篇文章。

本篇文章是对上篇文章的完善和补充。

原有问题

上篇文章在分析蓝牙聊天app时提到过“管理连接线程”,在该线程中无限循环读取 InputStream,如果读取异常,说明蓝牙中断。
而读取的方法也很简单,直接读取数据到字节数组中:

byte[] buffer = new byte[1024];mInStream.read(buffer);

之前以为给buffer分配的空间大点,就能保证一次接收到的数据是完整的。
然,非也!
这样做还会抢占紧张的内存,严重时甚至导致OOM!

分析问题

read(byte b[])方法调取了另一个重载方法read(b, 0, b.length),该方法的源码如下:

public int read(byte b[], int off, int len) throws IOException {    if (b == null) {        throw new NullPointerException();    } else if (off < 0 || len < 0 || len > b.length - off) {        throw new IndexOutOfBoundsException();    } else if (len == 0) {        return 0;    }    int c = read();    if (c == -1) {        return -1;    }    b[off] = (byte)c;    int i = 1;    try {        for (; i < len ; i++) {            c = read();            if (c == -1) {                break;            }            b[off + i] = (byte)c;        }    } catch (IOException ee) {    }    return i;}

再提取源码注释中的几个关键信息:
1. This method blocks until input data is available, end of file is detected, or an exception is thrown.
2. An attempt is made to read as many as len bytes, but a smaller number may be read.
The number of bytes actually read is returned as an integer
3. In every case, elements b[0] through b[off] and elements b[off+len] through b[b.length-1] are unaffected.

结合源码和注释,可以得出:
1. 该方法会阻塞直到有数据读入或到文件末尾或抛出异常;
2. 读取的字节数会尽可能和参数len一样大,但可能比它小,实际读取的字节数在返回值中。
3. 读取后,b[0]至b[off]和b[off+len]至b[b.length-1]的值没有变化,改变的只是b[off]至b[off+len]的值。

因此,每次读取的字节数是不确定的,当数据量大时,读取一次很可能就是不完整的数据。
而经过测试,蓝牙发送方发送一次数据,接收方哪怕通过多次读取把数据完整接收后,read()方法也不会返回-1,而是阻塞着等待下一段数据的到来。
于是,需要另外寻找”数据读取完毕”的临界点。

解决问题

一段数据哪怕分多次读取,相邻两次读取的间隔时间也是很快的,这和阻塞有很明显的区别。
于是可以利用倒计时来判断一段数据是否已经读取完整,具体逻辑如下:
1. 读取数据后拼接数据,开始一个短暂的倒计时。
2. 倒计时结束表示一段数据已经读取完整,开始使用数据。
3. 如果倒计时结束前又读取到新数据,则取消倒计时,重复步骤1。

核心代码如下:

private StringBuilder jsonBuilder = new StringBuilder();private BlueWaitingTimer timer = new BlueWaitingTimer();private class BlueWaitingTimer extends CountDownTimer {    public BlueWaitingTimer(long millisInFuture, long countDownInterval) {        super(millisInFuture, countDownInterval);    }    @Override    public void onTick(long millisUntilFinished) {    }    @Override    public void onFinish() {        //一段数据接收完毕,开始使用数据,使用后清空StringBuilder        jsonBuilder.delete(0, jsonBuilder.length());    }}private class ConnectedThread extends Thread {    @Override     public void run() {        byte[] buffer = new byte[1024];        int count;        while (true) {            try {                count = mInStream.read(buffer);                timer.cancel();                jsonBuilder.append(new String(buffer, 0, count, "UTF-8"));                timer.start();            } catch (IOException e) {                 break;            }        }    }}

注意:此处的BlueWaitingTimer不可以在线程ConnectedThread中实例化,否则倒计时结束时将被read方法阻塞得不到执行。

阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 九鼎记写完了么 九鼎记多少字 九鼎记目录 九鼎记 下载 九鼎记内容简介 九鼎记一共多少字 九鼎记介绍 九鼎记作者 九鼎记 精校 九鼎记全本txt下载 九鼎记诸葛青 九鼎记的续集 九鼎记好看么 九鼎记完本了吗 九鼎记 燃文 九鼎记好看不 我爱西红柿九鼎记 九鼎记 女主 吞噬星空和九鼎记 j九鼎记 九鼎记之我是腾青虎 九鼎记主角有几个老婆 九鼎记后传txt下载 九鼎记全文txt下载 九鼎记讲的是什么 九鼎记内容介绍 九鼎记有几个女主角 九鼎记txt全集下载 完整版 九鼎记思路客 从九鼎记开始 滕青山 九龙仓苏州国际金融中心 九龙仓集团 长沙九龙仓 九龙仓国际金融中心 九龙仓风华里 九龙仓年华里 苏州九龙仓碧堤雅苑 无锡九龙仓碧玺 无锡九龙仓玺园 九龙仓兰宫