netty:netty自带四种Docoder解码器
在这里放一下自己对netty长度解码器的理解
想看netty自定义解码器讲解可以直接跳过我自定义的编解码器
开始写之前文章的netty+动态代理的项目的时候,刚开始自己在网上找了一些编码器和解码器的写法,(不完全是自定义,也用到了Kyro)自定义写了一套,直接发送你要发的实体对象,算是先理解一下编解码器的原理。
KyroMsgDecoder
public class KyroMsgDecoder extends ByteToMessageDecoder {
public static final int HEAD_LENGTH = 4;
private Kryo kryo = new Kryo();
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
if (in.readableBytes() < HEAD_LENGTH) {
return;
}
in.markReaderIndex();
int dataLength = in.readInt();
if (dataLength < 0) {
ctx.close();
}
if (in.readableBytes() < dataLength) {
in.resetReaderIndex();
return;
}
byte[] body = new byte[dataLength];
in.readBytes(body);
Object o = convertToObject(body);
out.add(o);
}
private Object convertToObject(byte[] body) {
Input input = null;
ByteArrayInputStream bais = null;
try {
bais = new ByteArrayInputStream(body);
input = new Input(bais);
return kryo.readObject(input, Student.class);//这是重点,这个Student就是我的实体类
} catch (KryoException e) {
e.printStackTrace();
}finally{
IOUtils.closeQuietly(input);
IOUtils.closeQuietly(bais);
}
return null;
}
}
KyroMsgEncoder
public class KyroMsgEncoder extends MessageToByteEncoder<Student> {
private Kryo kryo = new Kryo();
//encode的参数直接写成实体类类型。
@Override
protected void encode(ChannelHandlerContext ctx, Student msg, ByteBuf out) throws Exception {
byte[] body = convertToBytes(msg);
int dataLength = body.length;
out.writeInt(dataLength);
out.writeBytes(body);
}
//这里也是
private byte[] convertToBytes(Student student) {
ByteArrayOutputStream bos = null;
Output output = null;
try {
bos = new ByteArrayOutputStream();
output = new Output(bos);
kryo.writeObject(output, student);
output.flush();
return bos.toByteArray();
} catch (KryoException e) {
e.printStackTrace();
}finally{
IOUtils.closeQuietly(output);
IOUtils.closeQuietly(bos);
}
return null;
}
}
netty提供了强大的编解码器框架,使得我们编写自定义的编解码器很容易,也容易封装重用。
在网络应用中需要实现某种编解码器,将原始字节数据与自定义的消息对象进行互相转换。网络中都是以字节码的数据形式来传输数据的,服务器编码数据后发送到客户端,客户端需要对数据进行解码。编解码器由两部分组成:编码器、解码器。
解码器:负责将消息从字节或其他序列形式转成指定的消息对象。
编码器:将消息对象转成字节或其他序列形式在网络上传输。
netty自带解码器
LineBasedFrameDecoder
LineBasedFrameDecoder是回车换行解码器,如果发送的消息以回车换行符结束标识,可以用LineBasedFrameDecoder进行解码。
@Override
protected void initChannel(SocketChannel arg) throws Exception {
arg.pipeline().addLast(new LineBasedFrameDecoder(1024));
arg.pipeline().addLast(new StringDecoder());
arg.pipeline().addLast(new UserServerHandler());
}
DelimiterBasedFrameDecoder
DelimiterBasedFrameDecoder是分隔符解码器,用户可以指定消息结束的分隔符,它可以自动选择分隔符。
@Override
public void initChannel(SocketChannel ch) throws Exception {
ByteBuf delimiter = Unpooled.copiedBuffer("$_".getBytes());
ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,delimiter));
ch.pipeline().addLast(new StringDecoder());
ch.pipeline().addLast(new UserServerHandler());
}
}
FixedLengthFrameDecoder
FixedLengthFrameDecoder是固定长度解码器,它能够按照指定的长度对消息进行自动解码,开发者不需要考虑TCP的粘包/拆包等问题,网上说是很实用的。
LengthFieldBasedFrameDecoder(我用的解码器!!!)
Netty提供了LengthFieldBasedFrameDecoder,自动屏蔽TCP底层的拆包和粘包问题,只需要传入正确的参数,即可轻松解决“读半包“问题。
@Override
protected void initChannel(SocketChannel ch) throws Exception {
/***
maxFrameLength - 发送的数据包最大的长度
lengthFieldOffset - 长度域偏移量,长度域位于整个数据包字节数组中的下标
lengthFieldLength - 长度域自己的字节数长度
lengthAdjustment – 长度域的偏移量矫正。 如果长度域的值,还包含了其他域(如长度域自身)长度,那么值为:包长 - 长度域的值 – 长度域偏移 – 长度域长
initialBytesToStrip – 丢弃的起始字节数。丢弃处于有效数据前面的字节数量。
***/
ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(1024,2,4,-4,6));
ch.pipeline().addLast(new StringDecoder(Charset.forName("UTF-8")));
ch.pipeline().addLast(new ClientHandler());
ch.pipeline().addLast(new StringEncoder());
}
学习时,看的一些厉害博主:好一个大布丁 (有部分是从他的一片文章参考的)
还有另外一个博主的文章:https://blog.csdn.net/u010853261/article/details/54575626
有帮助的话,来个三连吧!!!
本文地址:https://blog.csdn.net/wyyzy0420/article/details/110188295