我们知道netty中传输数据的核心是ByteBuf,它提供了多种数据读写方式,包括基本类型和byte数组读写方式。如果要在netty中传递这些数据,需要构建ByteBuf,然后调用ByteBuf中相应的方法写入相应的数据,然后套用netty中的标准模板即可使用。对于字节数组,如果每次都封装到ByteBuf中,传输起来有点麻烦。所以netty提供了一个基于字节的核心编解码器。什么是字节那么什么是字节呢?一个字节代表一个字节,也就是8bits。在二进制表示中,它的范围是-128-127。byte是JAVA中的基本类型。同时它还有一个wraptype,叫做Byte。先看Byte的定义:publicfinalclassByteextendsNumberimplementsComparableByte定义字节值访问:publicstaticfinalbyteMIN_VALUE=-128;公共静态最终字节MAX_VALUE=127;并且还提供了一些基本的工具方法。因为byte代表的是8位二进制,如果不算位操作,byte基本上是JAVA中最小的数据存储单元。所以JAVA中的所有对象都可以转化为byte。这里不讨论基本类型的转换。这里我们主要看字符串String与对象Object和字节数组之间的转换。我们先来看字符串String与字节数组的转换,即String与二进制的转换。基本的转换思路是对String中的字符进行编码,然后存储编码后的字符。String类本身提供了一个可以接受编码类型的getBytes方法。对于UTF-8,我们看一下转换方法的调用:publicstaticbyte[]stringToBytes(Stringstr)throwsUnsupportedEncodingException{returnstr.getBytes("utf-8");}publicstaticStringbytesToString(byte[]bs)throwsUnsupportedEncodingException{returnnewString(bs,"utf-8");直接调用String中的方法即可。如果是Object对象,由于Object本身没有提供转换方法,我们需要借助ByteArrayOutputStream的toByteArray方法和ByteArrayInputStream的readObject方法来实现字节数组与Object的转换,如下://Objecttoarraypublicbyte[]toByteArray(Objectobj)抛出IOException{oos.flush();返回bos.toArray();}}//数组到对象publicObjecttoObject(byte[]bytes)throwsIOException,ClassNotFoundException{try(ByteArrayInputStreambis=newByteArrayInputStream(bytes);ObjectInputStreamois=newObjectInputStream(bis)){returnois.readObject();}}netty的字节数组工具类的核心是ByteBuf,它提供了对大部分基本数据类型的读写方法。当然,如果要读取对象,还是需要将对象转换成byte,然后从ByteBuf中写入或读取。当然netty不需要这么复杂。Netty提供了一个Unpooled工具类来方便的进行字节数组和ByteBuf的转换。先看Unpooled方法提供的ByteBuff构造方法:ByteBufheapBuffer=buffer(128);ByteBufdirectBuffer=directBuffer(256);ByteBufwrappedBuffer=wrappedBuffer(newbyte[128],newbyte[256]);ByteBufcopiedBuffer=copiedBuffer(ByteBuffer.allocate(128));这是Unpooled提供的几种ByteBuf构造方法,其中heapBuffer代表在用户空间构造的buff,directBuffer代表直接在系统空间构造的buff。wrappedBuffer是建立在现有字节数组和ByteBuf之上的视图,copiedBuffer是字节数组、byteBuf和string的副本。这里我们需要使用wrappedBuffer方法将字节数组包装成一个ByteBuf:publicstaticByteBufwrappedBuffer(byte[]array){if(array.length==0){returnEMPTY_BUFFER;}returnnewUnpooledHeapByteBuf(ALLOC,array,array.length);}wrappedBuffer返回一个UnpooledHeapByteBuf对象,它本身是一个ByteBuf。在这里,字节数组作为构造函数传递到UnpooledHeapByteBuf中。这里的数组是UnpooledHeapByteBuf中的私有变量:byte[]数组;除了构造函数,UnpooledHeapByteBuf还提供了setArray方法来设置字节数组:privatevoidsetArray(byte[]initialArray){array=initialArray;tmpNioBuf=null;以下是如何从数组构建ByteBuf:publicByteBufsetBytes(intindex,ByteBuffersrc){ensureAccessible();src.get(数组,索引,src.remaining());归还这个;}从ByteBuf字节数组中读取,可以调用ByteBufUtil的getBytes方法:}netty中的byteencoder已经准备好了感谢东风,有了上面netty提供的工具类,我们就可以使用这些工具类来构建基于byte的encoder了。netty中基于字节的编解码器分别称为ByteArrayEncoder和ByteArrayDecoder。我们来看看这两个类是如何使用的。这里以一个典型的TCP/IP应用为例:ChannelPipelinepipeline=...;//解码器pipeline.addLast("frameDecoder",newLengthFieldBasedFrameDecoder(1048576,0,4,0,4));pipeline.addLast("bytesDecoder",newByteArrayDecoder());//编码器pipeline.addLast("frameEncoder",newLengthFieldPrepender(4));pipeline.addLast("bytesEncoder",newByteArrayEncoder());这里的LengthFieldBasedFrameDecoder和LengthFieldPrepender是以消息长度作为分割标准的分帧器。这里主要关注ChannelPipeline中添加的ByteArrayDecoder和ByteArrayEncoder。添加了byteencoder和decoder后,在handler中就可以直接使用byte数组了,如下图:它的实现很简单:);}}具体是使用Unpooled.wrappedBuffer方法将字节数组封装成一个ByteBuf,然后添加到out链表中。同样,我们看一下ByteArrayDecoder,它是一个实现比较简单的解码器:/将ByteBuf内容复制到字节数组out.add(ByteBufUtil.getBytes(msg));}}具体实现是调用ByteBufUtil.getBytes方法将ByteBuf转换为byte数组,然后添加到list对象中。总结如果你想在netty中传输二进制数据,netty提供的字节编码和解码器已经将繁琐的细节封装起来,你可以放心使用。本文已收录于http://www.flydean.com/14-2-netty-codec-bytes/最流行的解读,最深刻的干货,最简洁的教程,很多你不知道的小技巧等你来发现!欢迎关注我的公众号:《程序那些事儿》,懂技术,更懂你!