[编织消息框架][设计协议]解决粘包半包(中)
上节介绍问题出现跟处理方式,写数据部份已经实现
这节介绍如何读处理
处理流程分三部分
1.校验包是否合法
2.读取包内容
3.切割包
由于切割包用的是netty处理,所以只需集中精力解决前两个问题即可
ByteToMessageHandler.class
1 @Override 2 public QPacket decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception { 3 ByteBuf byteBuf = decoder.decode(ctx, in);//解释包 netty框架处理 4 if (byteBuf == null || !byteBuf.isReadable()) { //netty解释失败或未成功会返回null 5 return null; 6 } 7 if (byteBuf.readableBytes() < QPacket.PACK_FIXED_LENG) { //缓冲内容bytes长度少于包最小固定长度 8 return null; 9 } 10 final short headFlag = byteBuf.readShort(); //读取头部开始信息 2byte 11 final int packetLen = byteBuf.readInt(); //读取内容长度 12 final int endLen = 1; //尾部结束标志 1byte 13 //比较头部信息是否合法 14 if (headFlag != QMConfig.getInstance().getPacketHeadFlag(packetLen)) { 15 throw new QSocketException(QCode.SOCKET_ERROR_PCKET_FLAG, "解码包头标识不对"); 16 } 17 18 // 缓冲可读长度是否少于包长度 netty 处理过了 19 // if (byteBuf.readableBytes() - endLen < packetLen) { 20 // return null; 21 // } 22 23 final int mark = byteBuf.readerIndex(); //标记已读坐标,目的先读最后结束信息做比较 24 byteBuf.skipBytes(packetLen); //跳到最后结束标记 25 final byte endFlag = byteBuf.readByte(); //读取结束标记1byte 26 if (endFlag != QMConfig.getInstance().getPacketEndFlag(packetLen)) { 27 throw new QSocketException(QCode.SOCKET_ERROR_PCKET_FLAG, "解码包尾标识不对"); 28 } 29 byteBuf.readerIndex(mark);//还原坐标,开始处理QPacket 30 QPacket ret = QPacket.of(byteBuf, packetLen); //构造QPacket 31 byteBuf.skipBytes(endLen); //跳结束标记 32 return ret; 33 }
QPacket
1 public static QPacket of(ByteBuf byteBuf, int packetLen) { //按写入顺序读取 2 long sn = byteBuf.readLong(); //读包序列 3 short c = byteBuf.readShort();//读opcode 4 byte[] b = new byte[packetLen - QPacket.PACK_FIXED_LENG]; //算出内容实际大小 5 byteBuf.readBytes(b); //读取内容 6 long sid = byteBuf.readLong(); //读取sessionId 7 return of(c, sn, sid, null, b); 8 }
1 public static QPacket of(byte[] bytes) { 2 int offset = 0; 3 long sn = PacketUtil.readLong(offset, bytes); 4 short c = PacketUtil.readShort(offset += Long.BYTES, bytes); 5 byte[] b = PacketUtil.readBytes(offset += Short.BYTES, bytes.length - QPacket.PACK_FIXED_LENG, bytes); 6 long sid = PacketUtil.readLong(offset += b.length, bytes); 7 return of(c, sn, sid, null, b); 8 }
为什么没有直接用第二种方式去构造QPacket?
如果多一个临时对象array byte 会有损耗,无必要占创建时间,多一份内存开销
之前写入消息也采取相同处理方式,直接把数据传给netty ByteBuf 底层
1 public void writeToByteBuf(ByteBuf byteBuf) { 2 final int packetLen = toSize(); 3 byteBuf.writeShort(QMConfig.getInstance().getPacketHeadFlag(packetLen)); 4 byteBuf.writeInt(packetLen); 5 writeBytes(byteBuf); 6 byteBuf.writeByte(QMConfig.getInstance().getPacketEndFlag(packetLen)); 7 } 8 9 @Override 10 public byte[] toBytes() { 11 final int len = toSize(); 12 byte[] ret = new byte[len]; 13 int offset = 0; 14 PacketUtil.writeLong(offset, sn, ret); 15 PacketUtil.writeShort(offset += Long.BYTES, c, ret); 16 PacketUtil.writeBytes(offset += Short.BYTES, b, ret); 17 PacketUtil.writeLong(offset += b.length, sid, ret); 18 return ret; 19 }
作者: | solq |
博客地址: | http://www.cnblogs.com/solq111 |
博客版权: | 本文以学习、研究和分享为主,欢迎转载,但必须在文章页面明显位置给出原文连接。 如果文中有不妥或者错误的地方还望高手的你指出,以免误人子弟。如果觉得本文对你有所帮助不如【推荐】一下!如果你有更好的建议,不如留言一起讨论,共同进步! 再次感谢您耐心的读完本篇文章。 淘宝店: 海豚极货店 QQ群:9547527 |
如果你热爱生活、热爱编程、热爱吉他。扫一扫加我微信 |
我的新书《编织消息框架》目前进行中,感谢大家关注! |
本作品采用知识共享署名-非商业性使用-相同方式共享 2.5 中国大陆许可协议进行许可。 |