[编织消息框架][设计协议]解决粘包半包(中)

上节介绍问题出现跟处理方式,写数据部份已经实现

这节介绍如何读处理

处理流程分三部分

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   }

 

posted @ 2017-03-13 10:12  solq321  阅读(520)  评论(0编辑  收藏  举报