Google Protocol Buffer(简称 Protobuf)是一种轻便高效的结构化数据存储格式,平台无关、语言无关、可扩展,可用于通讯协议和数据存储等领域。
用于socket的数据传输在合适不过了。
编译很麻烦,所以谷歌提供了插件:https://github.com/google/protobuf-gradle-plugin
项目源码地址:https://github.com/google/protobuf
下面例子是在socket中的只用,解决了 tcp的粘包和分包问题:
/** * 发送封装消息 * * @return * @throws IOException */ public byte[] getByte1() throws IOException { MsgProtos.Msg msg = MsgProtos.Msg.newBuilder().setText("hello").build(); //在包体前 加入一个包长度字段 byte[] body = msg.toByteArray(); int bodyLen = body.length; //java int 4个字节 //protobuf 如果来编码这个int 数据 需要占用多少个字节 //最大占用 5个 字节 int headLen = CodedOutputStream.computeUInt32SizeNoTag(bodyLen); Log.e(TAG, "包头需要占用:" + headLen + "字节"); byte[] head = new byte[headLen]; //将 protobuf 编译的 bodyLen 写入到 head 里面 CodedOutputStream cos = CodedOutputStream.newInstance(head); cos.writeUInt32NoTag(bodyLen); cos.flush(); //head 表示包长度 // 包总长度 包头+包体长度 byte[] data = new byte[headLen + bodyLen]; System.arraycopy(head, 0, data, 0, headLen); System.arraycopy(body, 0, data, headLen, bodyLen); return data; }
/** * 接收解析 * * @param cache * @throws IOException */ static void processCache(ByteBuf cache) throws IOException { // 包头最大5个字节 byte[] buf = new byte[5]; for (int i = 0; i < buf.length; ++i) { // 如果cache中 不可以读取数据了 if (!cache.isReadable()) { cache.resetReadIndex(); return; } //1-5个字节都有可能 // 读取一个字节 buf[i] = cache.get(); //解码出长度 int length = CodedInputStream.newInstance(buf, 0, i + 1).readRawVarint32(); //可能就是包头=包体长度 if (length > 0) { //尝试去解析 protobuf 包体 //如果可读数据小于 包长度 if (cache.readableBytes() < length) { cache.resetReadIndex(); return; } //读取length 个 字节数据 byte[] b = cache.get(length); //处理完的数据 丢掉 不然cache会越来越大 cache.discardRead(); //反序列化 MsgProtos.Msg msg = MsgProtos.Msg.parseFrom(b); System.out.println(msg.getText()); } } }