# 《分布式IM系统》即时通讯后端服务-第02节:即时通讯后端服务自定义编解码器的设计与实现

作者:冰河
星球:http://m6z.cn/6aeFbs (opens new window)
博客:https://binghe.gitcode.host (opens new window)
文章汇总:https://binghe.gitcode.host/md/all/all.html (opens new window)
源码获取地址:https://t.zsxq.com/0dhvFs5oR (opens new window)
课程视频:https://t.zsxq.com/154VxZSq4 (opens new window)

沉淀,成长,突破,帮助他人,成就自我。

  • 本节难度:★★☆☆☆
  • 本节重点:对即时通讯后端服务的编解码器进行设计与实现,掌握Netty中自定义编解码器的设计与实现,并能够将其灵活应用到自身实际项目中。
  • 课程视频:https://t.zsxq.com/154VxZSq4 (opens new window)

大家好,我是冰河~~

数据在网络中传输时,离不开通信协议,同样,数据在应用层之间通信,也需要实现各种各样的网络协议。在项目开发过程中,我们就需要去构建适合自己业务场景的应用层协议。

# 一、前言

在前面的文章中,我们对即时通讯后端服务的通用代码进行设计和实现,总体上实现了即时通讯后端服务的主要系统框架,对于其他细节部分还有待完善。其中,就包括了编解码器的设计和实现。本节,就对即时通讯后端服务的编解码器进行设计和实现,以此满足数据在即时通讯后端服务中流转的最基本要求。

# 二、本章诉求

对即时通讯后端服务的编解码器进行设计与实现,掌握Netty中自定义编解码器的设计与实现,了解实现自定义编解码器与自定义通信协议的原理和落地方案,并能够将其灵活应用到自身实际项目中。

# 三、自定义通信协议

Netty是一个非常优秀的网络通信框架,在Netty中,提供了非常丰富的编解码器的抽象类,我们基于这些编解码器能够非常方便的进行扩展,并实现自定义的编解码器。

在Netty中,顾名思义,编解码器可以分成编码器和解码器两部分。

常用的编码器类型如下:

  • MessageToByteEncoder:将对象编码成字节流。
  • MessageToMessageEncoder:将一种消息类型编码成另外一种消息类型。

常用解码器类型如下:

  • ByteToMessageDecoder/ReplayingDecoder 将字节流解码为消息对象。
  • MessageToMessageDecoder 将一种消息类型解码为另外一种消息类型。

在Netty中,编解码器还可以细分成一次编解码器和二次编解码器。以解码器为例,解码器还可以分成一次解码器和二次解码器,一次解码器用于解决TCP粘包和拆包的问题,按照协议解析后得到字节流数据,此时这些字节流数据还不能供我们在项目中直接使用。如果我们需要将这些字节流数据转换成所需要的对象模型,就需要使用二次解码器实现。同理,编码器的过程与解码器的过程正好相反。

一次编解码器和二次编解码器分别如下所示。

  • 一次编解码器:MessageToByteEncoder/ByteToMessageDecoder。
  • 二次编解码器:MessageToMessageEncoder/MessageToMessageDecoder。

# 四、Netty编码器类

在Netty中,编码器类的类图如图2-1所示。


通过Netty中编码器类的类图可以看出,编码器类是ChanneOutboundHandler接口的实现类,主要操作的是Outbound的出站数据,主要包括:MessageToByteEncoder类和MessageToMessageEncoder类。

(1)MessageToByteEncoder类

MessageToByteEncoder类主要的作用就是将对象编码成字节流,在MessageToByteEncoder类中,提供了一个encode()抽象方法,我们继承MessageToByteEncoder类,实现encode()方法,即可实现自定义编码的功能,如下所示。

public class StringMessageToByteEncoder extends MessageToByteEncoder<String> {
    @Override
    protected void encode(ChannelHandlerContext channelHandlerContext, String Str, ByteBuf byteBuf) throws Exception {
        byteBuf.writeBytes(Str.getBytes());
    }
}
1
2
3
4
5
6

(2)MessageToMessageEncoder类

MessageToMessageEncoder类的主要作用是将一种格式的消息转换成另外一种格式的消息。并且MessageToMessageEncoder类最终的输出结果是对象列表,编码后的结果属于中间对象,最终仍然会转化成ByteBuf进行传输。

MessageToMessageEncoder类的子类包括:StringEncoder类、LineEncoder类、Base64Encoder类等。这里,我们以StringEncoder类为例进行说明,StringEncoder类继承了MessageToMessageEncoder类,并实现了MessageToMessageEncoder类的encode()方法。

源码详见:io.netty.handler.codec.string.StringEncoder#encode。

@Override
protected void encode(ChannelHandlerContext ctx, CharSequence msg, List<Object> out) throws Exception {
    if (msg.length() == 0) {
        return;
    }
    out.add(ByteBufUtil.encodeString(ctx.alloc(), CharBuffer.wrap(msg), charset));
}
1
2
3
4
5
6
7

# 五、Netty解码器类

在Netty中,解码器类的类图如图2-2所示。

# 查看完整文章

加入冰河技术 (opens new window)知识星球,解锁完整技术文章、小册、视频与完整代码