使用Netty进行编解码的操作过程详解

 更新时间:2019年07月15日 09:51:08   作者:正号先生  
这篇文章主要介绍了使用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();
    }
  }
}

可以看出客户端的代码与服务端基本相同,所以啊,如果能熟练掌握Netty,今后在自己的项目中运用上定制化编解码的传输,将会是一件十分简单的活路。

总结

无论是之前解决粘包拆包问题,还是这里的使用序列化框架来进行编解码。我相信读者学习到这里,对于Netty的使用都有了较为全面的了解。其实Netty帮我们解决了很多底层棘手问题,如客户端断连、句柄泄漏和消息丢失等等。所以我们才能十分简单开发出一个稳定的网络通讯项目。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • Java中String的JdbcTemplate连接SQLServer数据库的方法

    Java中String的JdbcTemplate连接SQLServer数据库的方法

    这篇文章主要介绍了Java中String的JdbcTemplate连接SQLServer数据库的方法,在研发过程中我们需要与其他系统对接的场景,连接SQLServer拉取数据,所以就用jdbc连接数据库的方式连接外部数据源,需要的朋友可以参考下
    2021-10-10
  • springboot整合kaptcha生成验证码功能

    springboot整合kaptcha生成验证码功能

    这篇文章主要介绍了springboot整合kaptcha生成验证码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-10-10
  • Java实现学生成绩管理系统

    Java实现学生成绩管理系统

    这篇文章主要为大家详细介绍了Java实现学生成绩管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-04-04
  • xxl-job定时任务配置应用及添加到springboot项目中实现动态API调用

    xxl-job定时任务配置应用及添加到springboot项目中实现动态API调用

    XXL-JOB是一个分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展,本篇文章主要是对xuxueli的xxl-job做一个简单的配置,以及将其添加到自己已有的项目中进行api调用,感兴趣的朋友跟随小编一起看看吧
    2024-04-04
  • java实现下载文件到默认浏览器路径

    java实现下载文件到默认浏览器路径

    这篇文章主要介绍了java实现下载文件到默认浏览器路径,具有很好的参考价值,希望对的大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-05-05
  • 详解Java如何通过装饰器模式扩展系统功能

    详解Java如何通过装饰器模式扩展系统功能

    这篇文章主要为大家详细介绍了Java如何通过装饰器模式扩展系统功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-04-04
  • Spring Boot中的过滤器拦截器监听器使用技巧汇总

    Spring Boot中的过滤器拦截器监听器使用技巧汇总

    本文将介绍在Spring Boot应用程序中使用过滤器、拦截器和监听器的使用技巧,我们将讨论它们之间的区别,以及何时使用它们,我们还将提供代码示例,以帮助您在自己的应用程序中使用它们
    2023-12-12
  • SpringBoot整合Retry实现错误重试过程逐步介绍

    SpringBoot整合Retry实现错误重试过程逐步介绍

    重试的使用场景比较多,比如调用远程服务时,由于网络或者服务端响应慢导致调用超时,此时可以多重试几次。用定时任务也可以实现重试的效果,但比较麻烦,用Spring Retry的话一个注解搞定所有,感兴趣的可以了解一下
    2023-02-02
  • Spring Boot 集成 Kafka的详细步骤

    Spring Boot 集成 Kafka的详细步骤

    Spring Boot与Kafka的集成使得消息队列的使用变得更加简单和高效,可以配置 Kafka、实现生产者和消费者,并利用 Spring Boot 提供的功能处理消息流,以下是 Spring Boot 集成 Kafka 的详细步骤,包括配置、生产者和消费者的实现以及一些高级特性,感兴趣的朋友一起看看吧
    2024-07-07
  • Springboot Thymeleaf实现HTML属性设置

    Springboot Thymeleaf实现HTML属性设置

    这篇文章主要介绍了Springboot Thymeleaf实现HTML属性设置,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2007-11-11

最新评论