解决粘包问题的几种方式
1、固定长度的信息
2、以特殊字符作为边界
3、自定义协议
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
* +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
* | magic |ver |headr len| full length | type | ser|comp| RequestId |time
* +-----+-----+-------+----+----+----+----+-----------+----- ---+--------+----+----+----+----+----+----+---+---+
* | |
* | body |
* | |
* +--------------------------------------------------------------------------------------------------------+----------------+
4个字节的魔术值 1个字节的版本号 2个字节的首部长度 4个字节的报文总长度 1个字节的请求类型 1个字节的序列化方式 1个字节的压缩方式 8个字节的请求id 8个字节的请求时间 + 若干请求体
请求类型有两种 一种是心跳请求 请求头为空 一种是其他请求 请求头不为空 所以请求总长度需要先判断类型 再进行计算
封装请求
// 4个字节的魔数值
byteBuf.writeBytes(MessageFormatConstant.MAGIC);
// 1个字节的版本号
byteBuf.writeByte(MessageFormatConstant.VERSION);
// 2个字节的头部的长度
byteBuf.writeShort(MessageFormatConstant.HEADER_LENGTH);
//总长度不知道 因为body不确定
//保存当前位置
fullLengthIndex = byteBuf.writerIndex();
//先往后移动4个字节
byteBuf.writerIndex(byteBuf.writerIndex() + MessageFormatConstant.FULL_FIELD_LENGTH);
//请求类型
byteBuf.writeByte(rpcRequest.getRequestType());
//序列化方式
byteBuf.writeByte(rpcRequest.getSerializeType());
//压缩类型
byteBuf.writeByte(rpcRequest.getCompressType());
// 8字节的请求id
byteBuf.writeLong(rpcRequest.getRequestId());
//请求时间
byteBuf.writeLong(rpcRequest.getTimeStamp());
判断是否是心跳请求
// 心跳请求 正常请求 不正常请求
if(rpcRequest.getRequestType() == RequestTypeEnum.HEARTBEAT_CHECK.getId() ){
// 处理一下总长度,其实总长度 = header长度
currentIndex = byteBuf.writerIndex();
byteBuf.writerIndex(MessageFormatConstant.FULL_FIELD_INDEX);
byteBuf.writeInt(MessageFormatConstant.HEADER_LENGTH);
byteBuf.writerIndex(currentIndex);
if (log.isDebugEnabled()) {
log.debug("客户端已编码心跳检测");
}
return;
}
正常类型
//body
byte[] body = null;
if (rpcRequest.getRequestPayload() != null) {
// 根据配置的方式进行序列化
Serializer serializer = SerializerFactory.getSerializer(rpcRequest.getSerializeType()).getImpl();
body = serializer.serialize(rpcRequest.getRequestPayload());
// 根据配置的方式进行压缩
Compressor compressor = CompressorFactory.getCompressor(rpcRequest.getCompressType()).getImpl();
body = compressor.compress(body);
}
if (body != null){
byteBuf.writeBytes(body);
bodyLength = body.length;
}
//保存当前位置
currentIndex = byteBuf.writerIndex();
byteBuf.writerIndex(fullLengthIndex);
byteBuf.writeInt(MessageFormatConstant.HEADER_LENGTH + bodyLength);
//归位
byteBuf.writerIndex(currentIndex);
if (log.isDebugEnabled()) {
log.debug("正常请求{{}]已经完成报文的编码。", rpcRequest.getRequestId());
}
接收方 以长度帧解码器 解码请求 具体如何使用 可以看这篇博客 写的很好 链接