Netty入门系列(3) --使用Netty进行编解码的操作

何为编解码,通俗的来说,我们需要将一串文本信息从A发送到B并且将这段文本进行加工处理,如:A将信息文本信息编码为2进制信息进行传输。B接受到的消息是一串2进制信息,需要将其解码为文本信息才能正常进行处理。

上章我们介绍的Netty如何解决拆包和粘包问题,就是运用了解码的这一功能。

java默认的序列化机制

使用Netty大多是java程序猿,我们基于一切都是对象的原则,经常会将对象进行网络传输,那么对于序列化操作肯定大家都是非常熟悉的。

一个对象是不能直接进行网络I/O传输的,jdk默认是将对象转换为可存储的字节数组来进行网络操作。基于JDK默认的序列化机制可以避免操作底层的字节数组,从而提升开发效率。

jdk默认的序列化机制虽然能给程序猿带来极大的方便,但是它也带来了许多问题:

无法跨语言。

序列化后的码流太大,会给网络传输带来极大的开销。

序列化的性能太低,对于高性能的网络架构是极其不友好的。

主流的编解码框架

Google的Protobuf。

Facebok的Thrift。

Jboss Marshalling

MessagePack

这几类编解码框架都有各自的特点,有兴趣的童鞋可以自己对其进行研究。

我们这里主要对MessagePack进行讲解。

MessagePack简介

MessagePack是一个高效的二进制序列化框架,它像JSON一样支持不同的语言间的数据交换,并且它的性能更快,序列化之后的码流也更小。

它的特点如下:

编解码高效,性能高

序列化之后的码流小,利于网络传输或存储

支持跨语言

MessagePack Java Api的使用

首先导包

<!-- https://mvnrepository.com/artifact/org.msgpack/msgpack --> <dependency> <groupId>org.msgpack</groupId> <artifactId>msgpack</artifactId> <version>0.6.12</version> </dependency>

使用API进行编码和解码

List<String> nameList = new ArrayList<String>(); nameList.add("Tom"); nameList.add("Jack"); MessagePack messagePack = new MessagePack(); //开始序列化 byte[] raw = messagePack.write(nameList); //使用MessagePack的模版,来接序列化后的字节数组转换为List List<String> deNameList = messagePack.read(raw,Templates.tList(Templates.TString)); System.out.println(deNameList.get(0)); System.out.println(deNameList.get(1)); System.out.println(deNameList.get(2)); Netty中如何使用MessagePack 编码器的实现 public class MsgpackEncoder extends MessageToByteEncoder { @Override protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception { MessagePack msgpack = new MessagePack(); //使用MessagePack对要发送的数据进行序列化 byte[] raw = msgpack.write(msg); out.writeBytes(raw); } } 解码器的实现 public class MsgpackDecoder extends MessageToMessageDecoder<ByteBuf> { @Override protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception { //从msg中获取需要解码的byte数组 final int length = msg.readableBytes(); byte[] b = new byte[length]; msg.getBytes(msg.readerIndex(), b,0,length); //使用MessagePack的read方法将其反序列化成Object对象,并加入到解码列表out中 MessagePack msgpack = new MessagePack(); out.add(msgpack.read(b)); } } 实现该编码器和解码器的Netty服务端 public class NettyServer { public void bind(int port) throws Exception { EventLoopGroup bossGruop = new NioEventLoopGroup(); EventLoopGroup workGroup = new NioEventLoopGroup(); ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(bossGruop, workGroup) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 1024) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { // TODO Auto-generated method stub socketChannel.pipeline() //添加支持粘包、拆包解码器,意义:从头两个字节解析出数据的长度,并且长度不超过1024个字节 .addLast("frameDecoder",new LengthFieldBasedFrameDecoder(1024, 0, 2,0,2)) //反序列化解码器 .addLast("msgpack decoder",new MsgpackDecoder()) //添加支持粘包、拆包编码器,发送的每个数据都在头部增加两个字节表消息长度 .addLast("frameEncoder",new LengthFieldPrepender(2)) //序列化编码器 .addLast("msgpack encoder",new MsgpackEncoder() //后续自己的业务逻辑 .addLast(new ServerHandler()); } }); try { ChannelFuture future = bootstrap.bind(port).sync(); future.channel().closeFuture().sync(); } catch (Exception e) { e.printStackTrace(); } finally { bossGruop.shutdownGracefully(); workGroup.shutdownGracefully(); } } } 实现该编码器和解码器的Netty客户端 public class NettyClient { private void bind(int port, String host) { EventLoopGroup group = new NioEventLoopGroup(); Bootstrap b = new Bootstrap(); b.group(group) .channel(NioSocketChannel.class) .option(ChannelOption.TCP_NODELAY, true) .handler(new ChannelInitializer<SocketChannel>(){ @Override protected void initChannel(SocketChannel socketChannel) throws Exception { // TODO Auto-generated method stub socketChannel.pipeline() .addLast("frameDecoder", new LengthFieldBasedFrameDecoder(1024, 0, 2, 0, 2)) .addLast("msgpack decoder", new MsgpackDecoder()) .addLast("frameEncoder", new LengthFieldPrepender(2)) .addLast("msgpack encoder", new MsgpackEncoder()) .addLast(new ClientHandler()); } }); try { ChannelFuture f = b.connect(host, port).sync(); f.channel().closeFuture().sync(); } catch (Exception e) { e.printStackTrace(); } finally { group.shutdownGracefully(); } } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wssydd.html