netty系列之:netty中的核心编码器bytes数组

简介: netty系列之:netty中的核心编码器bytes数组

目录



简介


我们知道netty中数据传输的核心是ByteBuf,ByteBuf提供了多种数据读写的方法,包括基本类型和byte数组的读写方法。如果要在netty中传输这些数据,那么需要构建ByteBuf,然后调用ByteBuf中对应的方法写入对应的数据,接着套用netty中标准的模板即可使用。


对于byte数组来说,如果每次都将其封装进ByteBuf中,再进行传输显得有些麻烦。于是netty提供了一个基于bytes的核心编码解码器。


byte是什么


那么byte是什么呢? byte表示的是一个字节,也就是8bits。用二进制表示就是-128-127的范围。byte是JAVA中的基础类型。


同时它还有一个wrap类型叫做Byte。


先看下Byte的定义:


public final class Byte extends Number implements Comparable<Byte>


Byte中定义了byte的取值访问:


public static final byte   MIN_VALUE = -128;
    public static final byte   MAX_VALUE = 127;


并且还提供了一些基本的工具方法。


因为byte表示的是一个8bits的二进制,如果不算位运算的话,byte基本上是JAVA中最小的数据存储单位了。所以JAVA中所有的对象都可以转换成为byte。


基础类型的转换这里就不多讲了。这里主要看一下字符串String和对象Object和byte数组之间的转换。


先来看下字符串String和byte数组之间的转换,也就是String和二进制之间的转换。


基本的转换思路就是将String中的字符进行编码,然后将编码过后的字符进行存储即可。


String类本身提供了一个getBytes方法,可以接受编码类型,以UTF-8来说,我们来看下转换方法的调用:


public static byte[] stringToBytes(String str) throws UnsupportedEncodingException {
       return str.getBytes("utf-8");
    }
    public static String bytesToString(byte[] bs) throws UnsupportedEncodingException {
       return new String(bs, "utf-8");
    }


直接调用String中的方法即可。


如果是Object对象的话,因为Object本身并没有提供转换的方法,所以我们需要借助于ByteArrayOutputStream的toByteArray方法和ByteArrayInputStream的readObject方法来实现byte数组和Object之间的转换,如下所示:


//对象转数组
    public byte[] toByteArray (Object obj) throws IOException {
        try(ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos)) {
            oos.writeObject(obj);
            oos.flush();
            return  bos.toByteArray();
        }
    }
    //数组转对象
    public Object toObject (byte[] bytes) throws IOException, ClassNotFoundException {
        try (
            ByteArrayInputStream bis = new ByteArrayInputStream (bytes);
            ObjectInputStream ois = new ObjectInputStream (bis)) {
            return ois.readObject();
        }
    }


netty中的byte数组的工具类


netty中的核心是ByteBuf,ByteBuf提供了大部分基础数据类型的read和write方法。当然如果要读取对象,那么还是需要将对象转换成为byte然后再写入或者从ByteBuf中读出。


当然,netty中不需要这么复杂,netty提供了一个Unpooled的工具类用来方便的将byte数组和ByteBuf进行转换。


先看下Unpooled方法提供的ByteBuff构建方法:


ByteBuf heapBuffer    = buffer(128);
   ByteBuf directBuffer  = directBuffer(256);
   ByteBuf wrappedBuffer = wrappedBuffer(new byte[128], new byte[256]);
   ByteBuf copiedBuffer  = copiedBuffer(ByteBuffer.allocate(128));


这是Unpooled提供的几种ByteBuf的构建方式,其中heapBuffer表示的是在用户空间构建的buff,directBuffer表示的是直接在系统空间构建的buff。wrappedBuffer是对现有的byte数组和ByteBuf之上构建的视图,而copiedBuffer是对byte数组,byteBuf和字符串的拷贝。


这里我们需要用到wrappedBuffer方法,将byte数组封装到ByteBuf中:


public static ByteBuf wrappedBuffer(byte[] array) {
        if (array.length == 0) {
            return EMPTY_BUFFER;
        }
        return new UnpooledHeapByteBuf(ALLOC, array, array.length);
    }


wrappedBuffer返回了一个UnpooledHeapByteBuf对象,这个对象本身就是一个ByteBuf。这里将byte数组作为构造函数传入UnpooledHeapByteBuf中。


这里的array是UnpooledHeapByteBuf中的私有变量:


byte[] array;


除了构造函数,UnpooledHeapByteBuf还提供了一个setArray的方法用来设置byte数组:


private void setArray(byte[] initialArray) {
        array = initialArray;
        tmpNioBuf = null;
    }


下面是如何从array中构建ByteBuf:


public ByteBuf setBytes(int index, ByteBuffer src) {
        ensureAccessible();
        src.get(array, index, src.remaining());
        return this;
    }


从ByteBuf中读取byte数组,可以调用ByteBufUtil的getBytes方法:


public static byte[] getBytes(ByteBuf buf) {
        return getBytes(buf,  buf.readerIndex(), buf.readableBytes());
    }


netty中byte的编码器


万事俱备只欠东风,有了上面netty提供的工具类,我们就可以使用这些工具类构建基于byte的编码器了。


netty中基于byte的编码解码器分别叫做ByteArrayEncoder和ByteArrayDecoder。


先来看下这两个类是如何使用的,这里以一个典型的TCP/IP应用为例:


ChannelPipeline pipeline = ...;
   // Decoders
   pipeline.addLast("frameDecoder",
                    new LengthFieldBasedFrameDecoder(1048576, 0, 4, 0, 4));
   pipeline.addLast("bytesDecoder",
                    new ByteArrayDecoder());
   // Encoder
   pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));
   pipeline.addLast("bytesEncoder", new ByteArrayEncoder());


这里的LengthFieldBasedFrameDecoder和LengthFieldPrepender是以消息长度为分割标准的frame分割器。这里我们主要关注ChannelPipeline中添加的ByteArrayDecoder和ByteArrayEncoder。


添加了byte的编码和解码器之后,就可以直接在handler中直接使用byte数组,如下所示:


void channelRead(ChannelHandlerContext ctx, byte[] bytes) {
       ...
   }


先来看下ByteArrayEncoder,这是一个编码器,它的实现很简单:


public class ByteArrayEncoder extends MessageToMessageEncoder<byte[]> {
    @Override
    protected void encode(ChannelHandlerContext ctx, byte[] msg, List<Object> out) throws Exception {
        out.add(Unpooled.wrappedBuffer(msg));
    }
}


具体就是使用Unpooled.wrappedBuffer方法byte数组封装成为ByteBuf,然后将其添加到out list中。


同样的,我们观察一下ByteArrayDecoder,这是一个解码器,实现也比较简单:


public class ByteArrayDecoder extends MessageToMessageDecoder<ByteBuf> {
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
         // copy the ByteBuf content to a byte array
        out.add(ByteBufUtil.getBytes(msg));
    }
}


具体的实现就是调用ByteBufUtil.getBytes方法,将ByteBuf转换成为byte数组,然后添加到list对象中。


总结



如果要在netty中传输二进制数据,netty提供的byte编码和解码器已经封装了繁琐的细节,大家可以放心使用。

相关文章
|
6月前
|
移动开发 编解码 Java
Netty编码器和解码器
Netty从底层Java通道读到ByteBuf二进制数据,传入Netty通道的流水线,随后开始入站处理。在入站处理过程中,需要将ByteBuf二进制类型解码成Java POJO对象。这个解码过程可以通过Netty的Decoder解码器去完成。在出站处理过程中,业务处理后的结果需要从某个Java POJO对象编码为最终的ByteBuf二进制数据,然后通过底层 Java通道发送到对端。在编码过程中,需要用到Netty的Encoder编码器去完成数据的编码工作。
|
设计模式 缓存 前端开发
深入理解 Netty编码流程及WriteAndFlush()的实现 (一)
深入理解 Netty编码流程及WriteAndFlush()的实现 (一)
433 0
|
6月前
|
编解码 安全 前端开发
Netty Review - StringEncoder字符串编码器和StringDecoder 解码器的使用与源码解读
Netty Review - StringEncoder字符串编码器和StringDecoder 解码器的使用与源码解读
250 0
|
XML 存储 编解码
Netty入门到超神系列-Netty使用Protobuf编码解码
当我们的Netty客户端和服务端进行通信时数据在传输的过程中需要进行序列化,比如以二进制数据进行传输,那么我们的业务数据就需要有相应的编码器进行编码为二进制数据,当服务端拿到二进制数据后需要有相应的解码器进行解码得到真实的业务数据。
163 0
|
网络协议 前端开发 Java
Netty核心知识
netty核心八股文,奉献给大家
398 0
|
存储 fastjson Java
|
缓存 安全 NoSQL
基于Netty,从零开发IM(四):编码实践篇(系统优化)
虽然 Netty 的性能很高,但是也不能保证随意写出来的项目就是性能很高的,所以本篇将主要讲解几个基于Netty的IM系统的优化实战技术点。
211 0
基于Netty,从零开发IM(四):编码实践篇(系统优化)
|
存储 Java Go
基于Netty,从零开发IM(三):编码实践篇(群聊功能)
接上两篇《IM系统设计篇》、《编码实践篇(单聊功能)》,本篇主要讲解的是通过实战编码实现IM的群聊功能,内容涉及群聊技术实现原理、编码实践等知识。
220 0
基于Netty,从零开发IM(三):编码实践篇(群聊功能)
|
搜索推荐 网络协议 Java
一个低级错误引发Netty编码解码中文异常
最近在调研Netty的使用,在编写编码解码模块的时候遇到了一个中文字符串编码和解码异常的情况,后来发现是笔者犯了个低级错误。这里做一个小小的回顾。
567 0
一个低级错误引发Netty编码解码中文异常
|
存储 算法 Java
netty系列之:netty中常用的对象编码解码器
我们在程序中除了使用常用的字符串进行数据传递之外,使用最多的还是JAVA对象。在JDK中,对象如果需要在网络中传输,必须实现Serializable接口,表示这个对象是可以被序列化的。这样就可以调用JDK自身的对象对象方法,进行对象的读写。 那么在netty中进行对象的传递可不可以直接使用JDK的对象序列化方法呢?如果不能的话,又应该怎么处理呢? 今天带大家来看看netty中提供的对象编码器。