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

前言

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

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

java默认的序列化机制

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

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

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

  1. 无法跨语言。
  2. 序列化后的码流太大,会给网络传输带来极大的开销。
  3. 序列化的性能太低,对于高性能的网络架构是极其不友好的。

主流的编解码框架

  1. Google的Protobuf。
  2. Facebok的Thrift。
  3. Jboss Marshalling
  4. MessagePack

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

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

MessagePack简介

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

它的特点如下:

  1. 编解码高效,性能高
  2. 序列化之后的码流小,利于网络传输或存储
  3. 支持跨语言

MessagePack Java Api的使用

  1. 首先导包
<!-- https://mvnrepository.com/artifact/org.msgpack/msgpack -->
<dependency>
    <groupId>org.msgpack</groupId>
    <artifactId>msgpack</artifactId>
    <version>0.6.12</version>
</dependency>
  1. 使用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帮我们解决了很多底层棘手问题,如客户端断连、句柄泄漏和消息丢失等等。所以我们才能十分简单开发出一个稳定的网络通讯项目。

原文地址:https://www.cnblogs.com/zhxiansheng/p/10887604.html

时间: 2024-08-29 02:47:12

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

[转]Netty入门(最简单的Netty客户端/服务器程序)

Java中的NIO是一种解决阻塞式IO问题的基本技术,但是NIO的编写对java程序员是有比较高的要求的.那么Netty就是一种简化操作的一个成熟的网络IO编程框架.这里简单介绍一个程序,代码是<netty in action>里面的,不过那个里面的实例有点问题,反正我没有跑成功,修改后成功.直接上代码: 一.服务器编写 Server代码,监听连接 1 package com.gerry.netty.server; 2 3 import io.netty.bootstrap.ServerBoo

[Netty] - Netty入门(最简单的Netty客户端/服务器程序)

Java中的NIO是一种解决阻塞式IO问题的基本技术,但是NIO的编写对java程序员是有比较高的要求的.那么Netty就是一种简化操作的一个成熟的网络IO编程框架.这里简单介绍一个程序,代码是<netty in action>里面的,不过那个里面的实例有点问题,反正我没有跑成功,修改后成功.直接上代码: 一.服务器编写 Server代码,监听连接 1 package com.gerry.netty.server; 2 3 import io.netty.bootstrap.ServerBoo

JAVA通信系列三:Netty入门总结

一.Netty学习资料 书籍<Netty In Action中文版> 对于Netty的十一个疑问http://news.cnblogs.com/n/205413/ 深入浅出Nettyhttp://wenku.baidu.com/view/7765bc2db4daa58da0114a4c.html Netty了解与小试 http://www.cnblogs.com/xd502djj/archive/2012/06/25/2561318.html Netty系列之Netty高性能之道[精彩]htt

【转】Netty系列之Netty编解码框架分析

http://www.infoq.com/cn/articles/netty-codec-framework-analyse/ 1. 背景 1.1. 编解码技术 通常我们也习惯将编码(Encode)称为序列化(serialization),它将对象序列化为字节数组,用于网络传输.数据持久化或者其它用途. 反之,解码(Decode)/反序列化(deserialization)把从网络.磁盘等读取的字节数组还原成原始对象(通常是原始对象的拷贝),以方便后续的业务逻辑操作. 进行远程跨进程服务调用时(

从入门到实战,Netty多线程篇案例集锦

从入门到实战,Netty多线程篇案例集锦 原创 2015-09-10 李林峰 InfoQ Netty案例集锦系列文章介绍 1|Netty的特点 Netty入门比较简单,主要原因有如下几点: Netty的API封装比较简单,将复杂的网络通信通过BootStrap等工具类做了二次封装,用户使用起来比较简单: Netty源码自带的Demo比较多,通过Demo可以很快入门: Netty社区资料.相关学习书籍也比较多,学习资料比较丰富. 但是很多入门之后的Netty学习者遇到了很多困惑,例如不知道在实际项

(入门篇 NettyNIO开发指南)第三章-Netty入门应用

作为Netty的第一个应用程序,我们依然以第2章的时间服务器为例进行开发,通过Netty版本的时间服务报的开发,让初学者尽快学到如何搭建Netty开发环境和!运行Netty应用程序. 如果你已经熟悉Netty    的基础应用,可以跳过本章,继续后面知识的学习.本章主要内容包括:.Netty开发环境的搭建.服务端程序TimeServer开发.客户端程序TimeClient开发时间服务器的运行和调试 3.1    Netty开发环境的搭建 首先假设你已经在本机安装了JDKI.7贯配置了JDK的环境

Netty学习总结(1)--Netty入门介绍

1.Netty是什么? Netty是一个基于JAVA NIO类库的异步通信框架,它的架构特点是:异步非阻塞.基于事件驱动.高性能.高可靠性和高可定制性. 2.使用Netty能够做什么? 开发异步.非阻塞的TCP网络应用程序: 开发异步.非阻塞的UDP网络应用程序: 开发异步文件传输应用程序: 开发异步HTTP服务端和客户端应用程序: 提供对多种编解码框架的集成,包括谷歌的Protobuf.Jboss marshalling.Java序列化.压缩编解码.XML解码.字符串编解码等,这些编解码框架可

【Netty】NIO框架Netty入门

Netty介绍 Netty是由JBOSS提供的一个java开源框架.Netty提供异步的.事件驱动的网络应用程序框架和工具,用以快速开发高性能.高可靠性的网络服务器和客户端程序. 也就是说,Netty 是一个基于NIO的客户.服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,服务端应用.Netty相当简化和流线化了网络应用的编程开发过程,例如,TCP和UDP的socket服务开发. 官网地址:http://netty.io/ 使用场景 Nett

Netty入门之WebSocket初体验

说一说IO通信 BIO通信: BIO即同步阻塞模式一请求一应答的通信模型,该模型最大的问题就是缺乏弹性伸缩能力,当客户端并发访问量增加后,服务端的线程个数和客户端并发访问数呈1:1的正比关系,由于线程是JAVA虚拟机非常宝贵的系统资源,当线程数膨胀之后,系统的性能将急剧下降,随着并发访问量的继续增大,系统会发生线程堆栈溢出.创建新线程失败等问题,并最终导致进程宕机或者僵死,不能对外提供服务. BIO的服务端通信模型: 采用BIO通信模型的服务端,通常由一个独立的Acceptor线程负责监听客户端