协议,这玩意儿相信大家肯定不陌生了,简单回顾一下协议的概念:网络协议是指一种通信双方都必须遵守的约定,两个不同的端,按照一定的格式对数据进行“编码”,同时按照相同的规则进行“解码”,从而实现两者之间的数据传输与通信。当自己想要打造一款IM通信程序时,对于消息的封装、拆分也同样需要设计一个协议,通信的两端都必须遵守该协议工作,这也是实现通信程序的前提。但为什么需要通信协议呢?因为TCP/IP中是基于流的方式传输消息,消息与消息之间没有边界,而协议的目的则在于约定消息的样式、边界等。
不知大家是否还记得之前我聊到的RESP客户端协议,这是Redis提供的一种客户端通信协议。如果想要操作Redis,就必须遵守该协议的格式发送数据。这个协议特别简单,如下:
1)首先要求所有命令,都以*开头,后面跟着具体的子命令数量,接着用换行符分割;
3)最后再拼接上具体的子命令,同样用换行符分割。
这样描述有些令人难懂,那就直接看个案例,例如一条简单set命令。如下:
按照Redis的规定,但凡满足RESP协议的客户端,都可以直接连接并操作Redis服务端,这也就意味着咱们可以直接通过Netty来手写一个Redis客户端。代码如下:
//基于Netty、RESP协议实现的Redis客户端publicclassRedisClient{//换行符的ASCII码staticfinalbyte[]LINE={13,10};
publicstaticvoidmain(String[]args){EventLoopGroupworker=newNioEventLoopGroup();Bootstrapclient=newBootstrap();
在上述这个案例中,也仅仅只是通过respCommand()这个方法,对用户输入的指令进行了转换。同时在上面通过Netty,与Redis的地址、端口建立了连接。在连接建立成功后,就会向Redis发送一条转换成RESP指令的set命令。接着等待Redis的响应结果并输出,如下:+OK因为这是一条写指令,所以当Redis收到执行完成后,最终就会返回一个OK,大家也可直接去Redis中查询,也依旧能够查询到刚刚写入的name这个键值。
前面咱们自己针对于Redis的RESP协议,对用户指令进行了封装,然后发往Redis执行。但对于这些常用的协议,Netty早已提供好了现成的处理器,想要使用时无需从头开发,可以直接使用现成的处理器来实现。比如现在咱们可以基于Netty提供的处理器,实现一个简单的HTTP服务器。代码如下:
Netty除开提供了HTTP协议的处理器外,还提供了DNS、HaProxy、MemCache、MQTT、Protobuf、Redis、SCTP、RTSP.....一系列协议的实现,具体定义位于io.netty.handler.codec这个包下,当然,咱们也可以自己实现自定义协议,按照自己的逻辑对数据进行编解码处理。很多基于Netty开发的中间件/组件,其内部基本上都开发了专属的通信协议,以此来作为不同节点间通信的基础,所以解下来咱们基于Netty也来自己设计一款通信协议,这也会作为后续实现聊天程序时的基础。
前面简单聊到过,所谓的自定义协议就是自己规定消息格式,以及自己实现编/解码器对消息实现封装/拆解,所以这里想要自定义一个消息协议,就只需要满足前面两个条件即可。因此实现如下:
上述自定义的协议,也就是一定规则的字节数据,每条消息数据的组成如下:1)魔数:使用第1~5个字节来描述,这个魔数值可以按自己的想法自定义;2)版本号:使用第6个字节来描述,不同数字表示不同版本;3)序列化算法:使用第7个字节来描述,不同数字表示不同序列化方式;4)消息类型:使用第8个字节来描述,不同的消息类型使用不同数字表示;5)消息序号:使用第9~12个字节来描述,其实就是一个四字节的整数;6)正文长度:使用第13~16个字节来描述,也是一个四字节的整数;7)消息正文:长度不固定,根据每次具体发送的数据来决定。
首先来定义两个拉群时用的消息体,如下:
前面单聊有单聊的会话管理机制,而实现多人群聊时,依旧需要有群聊的会话管理机制,首先封装了一个群聊实体类。如下:publicclassGroup{//聊天室名称privateStringname;//聊天室成员privateSet
前面客户端的功能菜单中,3对应着拉群功能,所以咱们需要对3做具体的功能实现。逻辑如下:>case"3":
这里就不重复赘述了,还是之前的套路,定义一个客户端用的消息体,如下:
依旧先来做客户端的实现,实现了客户端之后再去完成服务端的实现,客户端实现如下:
《跟着源码学IM(一):手把手教你用Netty实现心跳机制、断线重连机制》《跟着源码学IM(二):自已开发IM很难?手把手教你撸一个Andriod版IM》《跟着源码学IM(三):基于Netty,从零开发一个IM服务端》《跟着源码学IM(四):拿起键盘就是干,教你徒手开发一套分布式IM系统》《跟着源码学IM(五):正确理解IM长连接、心跳及重连机制,并动手实现》《跟着源码学IM(六):手把手教你用Go快速搭建高性能、可扩展的IM系统》《跟着源码学IM(七):手把手教你用WebSocket打造Web端IM聊天》《跟着源码学IM(八):万字长文,手把手教你用Netty打造IM聊天》《跟着源码学IM(九):基于Netty实现一套分布式IM系统》《跟着源码学IM(十):基于Netty,搭建高性能IM集群(含技术思路+源码)》《跟着源码学IM(十一):一套基于Netty的分布式高可用IM详细设计与实现(有源码)》《跟着源码学IM(十二):基于Netty打造一款高性能的IM即时通讯程序》(*本文)《SpringBoot集成开源IM框架MobileIMSDK,实现即时通讯IM聊天功能》