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

网友投稿 325 2023-01-02


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

前言

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

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

java默认的序列化机制

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

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

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

无法跨语言。

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

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

主流的编解码框架

Google的Protobuf。

Facebok的Thrift。

Jboss Marshalling

MessagePack

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

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

MessagePack简介

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

它的特点如下:

编解码高效,性能高

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

支持跨语言

MessagePack Java Api的使用

首先导包

org.msgpack

msgpack

0.6.12

使用API进行编码和解码

List nameList = new ArrayList();

nameList.add("Tom");

nameList.add("Jack");

MessagePack messagePack = new MessagePack();

//开始序列化

byte[] raw = messagePack.write(nameList);

//使用MessagePack的模版,来接序列化后的字节数组转换为List

List 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 {

@Override

protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List 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() {

@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(){

@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帮我们解决了很多底层棘手问题,如客户端断连、句柄泄漏和消息丢失等等。所以我们才能十分简单开发出一个稳定的网络通讯项目。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:java实现发送短信验证码
下一篇:后端接口测试工具(常见接口测试工具)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~