一、通讯数据格式
通讯协议的约定格式如下:
每一个数据包的长度不固定,但是前四个字节代表的意义是固定的
数据的长度取决于第3个字段的值
| 名称 | 长度 | 其他说明 | |
| 协议头 | 2字节 | 固定的两个字节,用以给协议分段 | |
| 数据类型 | 1字节 | 数据内容的类型,用以区别多种内容 | |
| 数据长度 | 1字节 | 后面数据内容的长度,1字节可表示最大长度是255 | |
| 数据 | n字节 | n取决于上一个字节中的数值 | |
| … | |||
| … | |||
| … | 
二、处理的难点
- 长度不固定,解析每一组数据时需要先想办法获取数据的长度
- 如果发送速度很快,收到一包可能有多组数据,需要一个while循环处理收到的一包的数据(这也就是粘包处理的初衷)
- 收到一包数据(本例中使用1024长度的缓冲区接收)可能将某个数据包截成两截,当前缓冲区未解析完的要保留下来,否则会丢数据
三、处理流程图
四、代码
在while(true)里面是读取tcp数据和进行粘包处理的代码
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |     class ReceiveThread extends Thread{         private boolean mReadSucc ;         private Handler mainThread = new Handler(Looper.getMainLooper());         @Override         public void run() {             super.run();             int readlen = 0;             byte[] buffer = new byte[1024];             ByteBuffer stickyBuffer = ByteBuffer.allocate(4096);             boolean foundHeader = false;             while (true){                 if(!mIsServiceRunning){                     break;                 }                 try {                     sleep(1);                 } catch (InterruptedException e) {                     e.printStackTrace();                 }                 try {                     mReadSucc = false;                     readlen = mInputStream.read(buffer);                     mReadSucc = true;                 } catch (IOException e) {                     e.printStackTrace();                 }                 if(!mReadSucc || readlen == 0){                     continue;                 }                 stickyBuffer.limit(4096);                 stickyBuffer.put(buffer, 0, readlen);                 stickyBuffer.flip();                 while (true){                     if(!stickyBuffer.hasRemaining()){                         stickyBuffer.compact();                         stickyBuffer.clear();                         break;                     }                     stickyBuffer.mark();                     if(stickyBuffer.remaining() < 4){                         int remaining = stickyBuffer.remaining();                         stickyBuffer.compact();                         stickyBuffer.position(remaining);                         stickyBuffer.limit(remaining);                         foundHeader = false;                         break;                     } else {                         short magicno = stickyBuffer.getShort();                         if(magicno != (short) 0xC0DE){                             continue;                         } else {                             foundHeader = true;                         }                     }                     if (foundHeader){                         int datatype = stickyBuffer.get() & 0xFF;                         int datalen = stickyBuffer.get() & 0xFF;                         if(stickyBuffer.remaining() < datalen) {                             stickyBuffer.reset();                             stickyBuffer.compact();                             break;                         } else {                             byte[] databuf = new byte[datalen];                             stickyBuffer.get(databuf);                             processSerialData(datatype, databuf);                         }                     }                 }             }         } | 
五、其他说明
- 串口通讯的粘包处理也可以使用此方法
