前言

最近闲暇时间研究Springboot,正好需要用到即时通讯部分了,虽然springboot 有websocket,但是我还是看中了 t-io框架。看了部分源代码和示例,先把helloworld敲了一遍,又把showcase代码敲了一遍,决定做一个总结。本篇文章并不会解释T-io是如何通讯的,而是从showcase这个给t-io初学者写的demo分析showcase的设计思路,以及为什么这么设计等。不过都是我个人理解,疏漏之处在所难免。

T-io简单介绍

代码结构很简单,首先我们知道通讯有客户端(client)和服务端(server).它们之间又会存在一些重复的业务处理逻辑,于是就有common的存在。那么整体的showcase下包含三部分:client,server,common。在代码分析之前呢,先简单介绍一下关于使用tio实现通讯的基础思路。我从tio官方截了两个图:

server端,我们只看红色部分。没错,要实现AioHandler中的encode,decode,handler方法。然后创建ServerGroupContext,最后调用start方法开启服务端。

client端,同样也需要实现AioHandler中的encode,decode,handler方法。不过客户端可以看到,多了一个心跳包(heartbeatPacket)。

通讯流程

我们知道,最基本的通讯流程就是,客户端发送消息到服务端,服务端处理之后,返回响应结果到客户端。或者服务端主动推送消息到客户端。因为客户端发送的消息格式不固定,所以t-io把编解码的权利交给开发者,这样可以自定义消息结构。那么Demo中由于采用的是同样的编解码方式。所以会有一个在common中的一个基础实现类。当然,由于消息类型的不同,具体的handler方法实现还是得区分不同的处理。

结构分析

以下的图都是根据我自己的理解画的,错误之处欢迎指正。

首先,我们看一下接口,类关系图:

首先,AioHandler,ClientAioHandler,ServerAioHandler 都是t-io中的Hander接口。我们从ShowcaseAbsAioHander开始看。上文中说道编解码属于通用部分,于是ShowcaseAbsAioHander实现了AioHandler接口中的 encode,decode方法。就是说不管客户端,服务端编码,解码方式都是同样的。其中有一个基础包 ShowcasePacket 。 它是贯穿整个通讯流程的。我们看一下代码:

public classShowcasePacket extends Packet {private bytetype;//消息类型(用于消息处理)private byte[] body;//消息体

}

其中,type消息类型是对应在common中的Type接口,它定义了不同的消息类型。

1 public interfaceType {2

3 /**4 * 登录消息请求5 */

6 byte LOGIN_REQ = 1;7 /**8 * 登录消息响应9 */

10 byte LOGIN_RESP = 2;11

12 /**13 * 进入群组消息请求14 */

15 byte JOIN_GROUP_REQ = 3;16 /**17 * 进入群组消息响应18 */

19 byte JOIN_GROUP_RESP = 4;20

21 /**22 * 点对点消息请求23 */

24 byte P2P_REQ = 5;25 /**26 * 点对点消息响应27 */

28 byte P2P_RESP = 6;29

30 /**31 * 群聊消息请求32 */

33 byte GROUP_MSG_REQ = 7;34 /**35 * 群聊消息响应36 */

37 byte GROUP_MSG_RESP = 8;38

39 /**40 * 心跳41 */

42 byte HEART_BEAT_REQ = 99;43

44 }

我们继续看上图,ShowcaseClientAioHandler 和 ShowCaseServerAioHandler这两个类的实现差不多。都是做基础消息处理。并且根据消息类型创建(获取)不同的消息处理器(handler)。实现代码如下:

@Overridepublic voidhandler(Packet packet, ChannelContext channelContext) throws Exception {//接收到的消息包

ShowcasePacket showcasePacket =(ShowcasePacket) packet;//获取消息类型

Byte type =showcasePacket.getType();//从handleMap中获取到具体的消息处理器

AbsShowcaseBsHandler> showcaseBsHandler = handlerMap.get(type);

//服务端的处理可能由于type类型不正确拿不到相应的消息处理器,直接return不给客户端响应。(或者统一返回错误消息)//处理消息

showcaseBsHandler.handler(showcasePacket, channelContext);return;

}

下面我们看一下,handler相关接口的设计。

可以看到,消息处理类使用了泛型。AbsShowcaseBsHandler实现了ShowcaseBsHandlerIntf中的handler方法。并且定义了一个抽象方法 handler,其中多了T bsBody 参数。可以知道,他对消息的实现,就是将消息字符转换为具体的消息对象,然后在调用具体的消息处理器处理相应的消息逻辑。代码如下:

public abstract class AbsShowcaseBsHandlerimplements ShowcaseBsHandlerIntf {private static Logger log = LoggerFactory.getLogger(AbsShowcaseBsHandler.class);/**

*

* @author tanyaowu*/

publicAbsShowcaseBsHandler() {

}//抽象方法,具体是什么类型的由子类实现

public abstract ClassbodyClass();

@OverridepublicObject handler(ShowcasePacket packet, ChannelContext channelContext) throws Exception {

String jsonStr= null;

T bsBody= null;if (packet.getBody() != null) {//将body转化为string

jsonStr = newString(packet.getBody(), Const.CHARSET);//根据类型反序列化消息,得到具体类型的消息对象

bsBody =Json.toBean(jsonStr, bodyClass());

}//调用具体的消息处理的实现

returnhandler(packet, bsBody, channelContext);

}//抽象方法,由每个消息处理类来实现具体的消息处理逻辑

public abstractObject handler(ShowcasePacket packet, T bsBody, ChannelContext channelContext) throws Exception;

}

我们以登录消息为例,分析具体消息处理流程。

首先客户端发起登录请求。(比如用户名:panzi,密码:123123)

LoginReqBody loginReqBody = newLoginReqBody();

loginReqBody.setLoginname(loginname);

loginReqBody.setPassword(password);//具体的消息都会包装在ShowcasePacket中(byte[] body)

ShowcasePacket reqPacket = newShowcasePacket();//这里呢就是传相应的消息类型

reqPacket.setType(Type.LOGIN_REQ);

reqPacket.setBody(Json.toJson(loginReqBody).getBytes(ShowcasePacket.CHARSET));//调用 t-io 发送消息方法

Aio.send(clientChannelContext, reqPacket);

服务端收到消息。这时候我们回过头看 ShowcaseServerAioHandler中的 handle方法。(上文中有介绍)此时消息类型为Type.LOGIN_REQ.可以很容易的想到,需要用 LoginReqHandler来处理这条消息。

我们看一下LoginReqHandler的具体实现

@OverridepublicObject handler(ShowcasePacket packet, LoginReqBody bsBody, ChannelContext channelContext) throws Exception {

log.info("收到登录请求消息:{}", Json.toJson(bsBody));//定义响应对象

LoginRespBody loginRespBody = newLoginRespBody();//模拟登录,直接给Success

loginRespBody.setCode(JoinGroupRespBody.Code.SUCCESS);//返回一个模拟的token

loginRespBody.setToken(newToken());//登录成功之后绑定用户

String userid =bsBody.getLoginname();

Aio.bindUser(channelContext, userid);//给全局Context设置用户ID

ShowcaseSessionContext showcaseSessionContext =(ShowcaseSessionContext) channelContext.getAttribute();

showcaseSessionContext.setUserid(userid);//构造响应消息包

ShowcasePacket respPacket = newShowcasePacket();//响应消息类型为 Type.LOGIN_RESP

respPacket.setType(Type.LOGIN_RESP);//将loginRespBody转化为byte[]

respPacket.setBody(Json.toJson(loginRespBody).getBytes(ShowcasePacket.CHARSET));//发送响应到客户端(告诉客户端登录结果)

Aio.send(channelContext, respPacket);return null;

}

这个时候就要到客户端处理了。同理,客户端处理拿到具体的处理器(LoginRespHandler)

看一下客户端消息处理代码

@OverridepublicObject handler(ShowcasePacket packet, LoginRespBody bsBody, ChannelContext channelContext) throws Exception {

System.out.println("收到登录响应消息:" +Json.toJson(bsBody));if(LoginRespBody.Code.SUCCESS.equals(bsBody.getCode())) {

ShowcaseSessionContext showcaseSessionContext=(ShowcaseSessionContext) channelContext.getAttribute();

showcaseSessionContext.setToken(bsBody.getToken());

System.out.println("登录成功,token是:" +bsBody.getToken());

}return null;

}

这样,整个消息流程就结束了。为了更清晰一点,我们将它以流程图的形式展现。

总结

虽然一个简单的Showcase,但是作者也是用了心思。通过这个例子可以既让我们学习到如何使用t-io,又能领略到程序设计的魅力,一个小小demo都这么多东西,看来读源代码之路还是比较遥远啊。以上是我对Showcase的代码理解,多有不当之处敬请指正。

java的showcase_通讯框架 t-io 学习——给初学者的Demo:ShowCase设计分析相关推荐

  1. java中talent-aio_通讯框架:talent-aio实例

    简 介 talent-aio是基于java aio实现的即时通讯框架,源于作者另一个久经考验的talent-nio框架,但在易用性.性能及代码可读性方面又远远超越了talent-nio.官网地址:ht ...

  2. 通讯框架 t-io 学习——给初学者的Demo:ShowCase设计分析

    前言 最近闲暇时间研究Springboot,正好需要用到即时通讯部分了,虽然springboot 有websocket,但是我还是看中了 t-io框架.看了部分源代码和示例,先把helloworld敲 ...

  3. Netty,Tcp,socket的java框架,netty学习

    最新更新,报文发送,机器终端(车)与服务端 先学习一下基本内容,以下是基于基本内容 互相转换:byte(字节,字节是数字单位,他的数组是十进制内容),bit(二进制内容,不用操心这部分),十六进制0x ...

  4. Java通讯框架介绍

    Java通讯框架介绍 Java通讯框架,有时也被称为网络服务器,其实就是封装IO操作,并提供更高级的API接口.目前比较流行的框架就是:MINA.Cindy.QuickServer等.前段时间为了缩短 ...

  5. Java的3大框架都学习什么呢?

    Java是互联网行业的第一编程语言,相信大家都已经有了解了,事实也确实如此,Java还是世界第一编程语言,在学习Java的过程中,框架是程序员们必学的知识点,而且是十分重要的应用,Spring.Str ...

  6. CGLIB依赖ASM(关于java字节码框架ASM的学习)

    本文转自: http://www.cnblogs.com/liuling/archive/2013/05/25/asm.html 一.什么是ASM ASM是一个java字节码操纵框架,它能被用来动态生 ...

  7. Java IO学习笔记总结

    Java IO学习笔记总结 前言 前面的八篇文章详细的讲述了Java IO的操作方法,文章列表如下 基本的文件操作 字符流和字节流的操作 InputStreamReader和OutputStreamW ...

  8. Java学习-07 IO学习

    Java学习-07 IO学习 I : 即input,代表读取.O:即output,代表输出. 1.File 主要字段: 示例: System.out.println(File.pathSeparato ...

  9. java日志框架(一)JUL 学习 ,这个是什么,他在代码中如何使用,一篇文章讲清楚

    这里写目录标题 JUL 是什么 JUL组件介绍 代码中如何使用(控制台输出) 日志级别 自定义输出级别 输出日志到文件(磁盘文件中) 日志对象父子关系 配置文件 使用方法总结 JUL 是什么 JUL全 ...

最新文章

  1. 在WPF中使用WinForm控件方法
  2. qchart画完以后删除_画错了,重新画一幅吧!”这句话对学画画的孩子来说,伤害有多大?...
  3. bbsmax mysql_Problems with MMM for mysql(译文)
  4. JEPaas代码_((列表)输入字段值而改变值
  5. Docker容器的自动化监控实现
  6. linux 查看 CPU 使用率
  7. apollo集群部署_egg框架对接Apollo
  8. c#中高效的excel导入oracle的方法(转)
  9. 让WebStorm支持dojo的智能提示
  10. fltk在UbuntuLinux中搭建和测试-《C++程序设计原理与实践》Chapter12:显示模型 环境构建...
  11. 天猫京东618下单金额近万亿;苹果或选择印度组装新款iPhone SE;Adobe将于12月31日终止支持Flash| 极客头条...
  12. 银联公钥加密java实现_【技术贴】银联加密算法 (收藏版)
  13. CNode社区(React)
  14. 将VSCode添加到鼠标右键菜单
  15. homelede软路由设置方法_小米路由器3 5G WiFi设置方法
  16. 【数理统计】假设检验
  17. 用Python一键生成属于自己的QQ历史报告,看看你对自己的QQ了解程度有多深?
  18. c语言链表单值化,《编译原理及实践教程》第3章词法分析.ppt
  19. 工业大数据漫谈4:工业大数据的作用
  20. 解决:Cause: java.sql.SQLException: Field ‘id‘ doesn‘t have a default value

热门文章

  1. java毕业设计垃圾分类网站Mybatis+系统+数据库+调试部署
  2. 计算机教室标语6个字,班级有趣标语教室标语
  3. 2018普通本科专业目录计算机类,教育部公布新版本科专业目录专业少了100多个...
  4. 华为跌倒,联想全面反攻,已在手机和平板电脑市场反超
  5. 《上海市战略性新兴产业发展专项资金管理办法》的通知
  6. mongodump和mongorestore实战
  7. mongodb 百万_1亿条记录的MongoDB数据库随机查询性能测试
  8. npm中 install -save 和 -save-dev以及缩写形式
  9. Python迭代器与生成器
  10. 互联网公司校招Java面试题总结及答案——网易