目录

Netty实现自定义通信协议

Netty实现自定义通信协议

概述

在网络编程中,无论使用netty还是其它的socket通讯框架,都是通过TCP或UDP传输二进制流。发送方把要发送的对象转化成二进制流发送出去;接收方把接收到的二进制流转化为对象进行处理。

为了能让接收方和发送方能对同一个二进制流有相同的认识,双方必须提前约定好一个协议,即对象如何转化为二进制流,二进制流如何转化为对象,这样通信双方才不会产生误解。

自定义通信协议

在 项目中,定义如下通信协议:

https://i-blog.csdnimg.cn/blog_migrate/7ee32c0fc94cfae386840ef1e6b02315.png

魔数 :4字节,一般为固定值,本项目中使用0x88888888。一般我们的应用于某个端口对外开放,为了防止该端口被意外调用,我们可以在收到报文后,取前4个字节与魔数比对,如果不相同,则直接拒绝并关闭连接。

版本号 : 1字节,一般是预留字段,为了支持协议升级(这种情况极少出现)。

序列化算法 :1字节,表示如何将java对象转化为二进制数据,以及如何反序列化。

指令 :1字节,表示该消息的意图,如私聊、群聊、登录等。最多支持256种指令。

数据长度 :4字节,表示该字段后数据部分的长度。

数据 :具体数据的内容。每种指令对应的数据是不同的。

序列化算法

本项目为了简单起见,使用json序列化算法。将Java对象转换成json字符串,再转化为二进制数据,代码如下:

https://i-blog.csdnimg.cn/blog_migrate/98bf26636fc19b74a2b9e2b53ffc1b14.png

https://i-blog.csdnimg.cn/blog_migrate/0a4ae8ce609b7072e409084dcd6e0b4e.png

首先定义Serializer接口,serialize方法用于将对象序列化为二进制数据,deSerialize方法用于将二进制反序列化成对象。getSerializerAlgorithm方法返回序列化算法。

JsonSerializer是Serializer的实现。

指令设计

定义Packet类,作为所有指令的基类,其中getCommand方法为抽象方法,需由子类实现,返回具体的指令类型。

https://i-blog.csdnimg.cn/blog_migrate/daa7b2e2ac71247344941cbedf1e741d.png

登录指令如下,登录时需要发送userId,useName,password等信息,以及指令command:

https://i-blog.csdnimg.cn/blog_migrate/200413bb978084591558dc6021282de4.png

指令类型如下:

https://i-blog.csdnimg.cn/blog_migrate/8428b1c07f723d9f3ad8f39d8504c9db.png

编解码实现

定义好序列化算法和指令之后,就可以进行编解码的实现了。编码即将通信包转化为二进制;解码即将二进制转化为通信包。

编码过程比较简单,代码如下,参照注释即可明白,ByteBuf里即是最后要发送的二进制数据:

https://i-blog.csdnimg.cn/blog_migrate/3b6b1b941860743c425b99aa9f07c91e.png

这里暂时跳过魔数和版本校验,获取到序列化算法、指令、数据长度和数据内容。根据指令我们可以知道请求类型是什么(如登录请求LoginRequestPacket、群聊请求GroupChatRequestPacket),根据序列化算法,将数据内容反序列化成目标对象,解码结束。

可以看到,编码与解码是相反的过程。

总结

基于netty作为网络通信基础组件时,我们必须要做如下几个步骤:

  • 定义通讯协议,通信双方需对此协议有一致的理解;
  • 编码,将Java对象转化为二进制;
  • 解码,将二进制转化为Java对象;
  • 业务处理

如果采用http、websocket等公有协议通信,netty提供了许多类可以实现步骤1,2,3,无需我们编码实现,只需调用相应的类和方法即可。

项目地址:

参考文档:

《netty入门实战:仿写微信IM及时通讯系统》

欢迎关注公众号:程序员顺仔 ,回复【资料】,即可获得架构进阶电子书籍

https://i-blog.csdnimg.cn/blog_migrate/64906b74aa9debb0de04b3404b435218.png