在进行netty的开发中,需要对数据进行编解码
。
netty 提供的解码器
DelimiterBasedFrameDecoder
解决TCP的粘包解码器StringDecoder
消息转成String解码器LineBasedFrameDecoder
自动完成标识符分隔解码器FixedLengthFrameDecoder
固定长度解码器,二进制Base64Decoder
base64解码器
netty 提供的编码器
Base64Encoder
base64编码器StringEncoder
消息转成String编码器LineBasedFrameDecoder
自动完成标识符分隔编码器MessageToMessageEncoder
根据 消息对象 编码为消息对象
对于 netty的数据传递都是ByteBuf,我们一般重写以上的解码器、编码器来实现自己的逻辑
BtyeBuf读操作主要提供以下功能:
- readByte:取1字节的内容;
- skipBytes: 跳过内容
- readUnsignedByte:取1字节的内容,返回((short) (readByte() & 0xFF));
- readShort:取2字节的内容,返回转换后的short类型;
- readUnsignedShort:取2字节的内容,返回readShort() & 0xFFFF;
- readMedium:取3字节的内容,返回转换后的int类型;
- readUnsignedMedium:取3字节的内容,返回转换后的int类型;
- readInt:取4字节的内容;
- readUnsignedInt:取4字节的内容,返回readInt() & 0xFFFFFFFFL;
- readLong:取8字节的内容;
- readChar:取1字节的内容;
- readFloat:取4字节的int内容,转换为float类型;
- readDouble:取8字节的long内容,转换为double类型;
- readBytes:取指定长度的内容,返回ByteBuf类型;
- readSlice:取指定长度的内容,返回ByteBuf类型;
- readBytes:取指定长度的内容到目标容器。
写操作
写操作提供的功能主要是往ByteBuf中写入byte内容,不再一一赘述。主要区别在于写入前根据类型转换为相对应长度的byte数组。
主要函数是:
- writeBoolean
- writeByte
- writeShort
- writeMedium
- writeInt
- writeLong
- writeChar
- writeFloat
- writeDouble
- writeBytes
- writeZero
边界值安全
不论读或写,肯定会存在ByteBuf数据为空或满的情形,作为数据容器,要存在边界值检查,确保读写安全。
DelimiterBasedFrameDecoder 解决TCP的粘包解码器
IODecoder 继承
/**
* 解码
* DelimiterBasedFrameDecoder 防止沾包
*/
public class IODecoder extends DelimiterBasedFrameDecoder {
public static final AttributeKey<DeviceSession> KEY = AttributeKey.valueOf("IO"); // 保存
private static final Logger log = Logger.getLogger(IODecoder.class);
// 防止 沾包 分隔符
private static ByteBuf delimiter = Unpooled.copiedBuffer("\n".getBytes()); // 沾包 分割符 \n
private static int maxFrameLength = 1024 * 6; //数据大小
public IODecoder() {
super(maxFrameLength, delimiter);
}
/**
* 重新 自定义解码
*/
@Override
protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
// 对数据 buffer 解码
return super.decode(ctx, buffer);
}
}
MessageToMessageEncoder 编码器
/**
* 指令 编码
* MessageToMessageEncoder<PushEntity>
* 把 PushEnty 编码为string
*/
public class IOEncoder extends MessageToMessageEncoder<PushEntity> {
private static final Logger LOG = Logger.getLogger(IOEncoder.class);
public IOEncoder() {
super();
}
/**
* 重写 编码
*/
@Override
protected void encode(ChannelHandlerContext ctx, PushEntity msg, List<Object> out) throws Exception {
try {
PushEntity push = (PushEntity) msg;
}
// 以字符串 形式 发送
out.add(ByteBufUtil.encodeString(ctx.alloc(), CharBuffer.wrap(msg.toString()), Charset.defaultCharset()));
} catch (Exception e) {
e.printStackTrace();
}
}
}
FixedLengthFrameDecoder 固定长度解码器,二进制
/**
*
* 功能描述:协议消息解码器
* 把 btyeBuf 转为 RootMessage对象
*
*/
public class GT06MsgDecoder extends LengthFieldBasedFrameDecoder
{
public GT06MsgDecoder()
{
super(65540, 2, 1, 2, 0); //继承
}
/*
* 重写 解码
*/
@Override
public Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception
{
ByteBuf frame = (ByteBuf) super.decode(ctx, in);
// 读取 ByteBuf 是根据 位数来读取的
try
{
if (frame == null)
{
return null;
}
int frameLen = frame.readableBytes();
// 起始位
byte[] header = new byte[GT06Constant.START_DELIMITER_LEN];
frame.readBytes(header);
// 是否是0x79 0x79 开头的扩展包
boolean extPacket = false;
if(Arrays.equals(GT06Constant.PACKET_START_EXT, header))
{
extPacket = true;
}
int contentLen = MessageUtils.getContentLen(frameLen, extPacket);
// 跳过包长度
frame.skipBytes(MessageUtils.getPacketSizeLen(extPacket));
// 消息内容
byte[] msgContent = new byte[contentLen];
// 消息序列号
byte[] sequence = new byte[GT06Constant.MESSAGE_SERIAL_LEN];
// crc校验码
byte[] crc = new byte[GT06Constant.CRC_ITU_LEN];
// 终止符
byte[] endDelimiter = new byte[GT06Constant.END_DELIMITER_LEN];
return new RootMessage(action, sequence, msgContent);
}
finally
{
if(frame != null)
{
frame.release();
}
}
}