8月 222019
一、通讯数据格式
通讯协议的约定格式如下:
每一个数据包的长度不固定,但是前四个字节代表的意义是固定的
数据的长度取决于第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); } } } } } |
五、其他说明
- 串口通讯的粘包处理也可以使用此方法
Sorry, the comment form is closed at this time.