上节介绍问题出现跟处理方式,写数据部份已经实现
这节介绍如何读处理
处理流程分三部分
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 }