Mina 架构与优化指南

本贴最后更新于 2252 天前,其中的信息可能已经东海扬尘

MINA 架构

这里,我借用了一张 Trustin Lee 在 Asia 2006 的 ppt 里面的图片来介绍 MINA 的架构。

Remote Peer 就是客户端,而下方的框是 MINA 的主要结构,各个框之间的箭头代表数据流向。

大家可以对比刚刚的例子来看这个架构图,IoService 就是整个 MINA 的入口,负责底层的 IO 操作,客户端发过来的消息就是由它处理。刚刚我们使用的 IoAcceptor 就是一个 IoService,之所以抽象成 IoService,是因为 MINA 用同样的架构来处理服务器和客户端编程,IoService 的另一个子类就是 IoConnector,用于客户端。不过根据笔者的使用经验,使用非阻塞的模型进行客户端编程非常的不方便,你最好寻求其他的阻塞通讯框架。

IoService 把数据转化成一个一个的事件,传递给 IoFilterChain。你可以加入一连串的 IoFilter,进行各种功能。笔者的建议是将一些功能性的,业务不相关的代码,用 IoFilter 来实现,使得整个应用结构更清晰,也方便代码重用。

被 IoFilter 处理过的事件,发送给 IoHandler,然后我们在这里实现具体的业务逻辑。这个部分很简单,如果你有 Swing 的使用经验的话,你会发现它跟 Swing 的事件非常相像,你要做的事情,仅仅是重载你需要的方法,然后编写具体的业务功能。在这其中,最重要的一个方法就是 messageReceived 了。

值得留意的是一个 IoSession 的类,每一个 IoSession 实例代表这一个连接,我们需要对连接进行的任何操作都通过这个类来实现。

从 IoHandler 通过调用 IoSession.write 等方法向客户端发送的消息,会通过跟输入数据相反的次序依次传递,直至由 IoService 负责把数据发送给客户端。

这就已经是 MINA 的全部,是不是很简单。

接下来,我会详细介绍我们编写具体代码的时候主要涉及到的三个类,IoHandler、IoSession 和 IoFilter。

IoHandler

MINA 的内部实现了一个事件模型,而 IoHanlder 则是所有事件最终产生响应的位置。每一个方法的名字很明确表明该事件的含义。messageReceived 是接收客户端消息的事件,我们应该在这里实现业务逻辑。messageSent 是服务器发送消息的事件,一般情况下我们不会使用它。sessionClosed 是客户端断开连接的事件,可以在这里进行一些资源回收等操作。值得留意的是,客户端连接有两个事件,sessionCreated 和 sessionOpened,两者稍有不同,sessionCreated 是由 I/O processor 线程触发的,而 sessionOpened 在其后,由业务线程触发的,由于 MINA 的 I/O processor 线程非常少,因此如果我们真的需要使用 sessionCreated,也必须是耗时短的操作,一般情况下,我们应该把业务初始化的功能放在 sessionOpened 事件中。

细心的读者可能会发现,我们刚刚的例子继承的是 IoHandlerAdapter,IoHandlerAdapter 其实就是一个 IoHanlder 的空的实现,这样我们就可以不用重载不感兴趣的事件。

IoSession

IoSession 是一个接口,MINA 里很多的地方都使用接口,很好地体现了面向接口编程的思想。它提供了对当前连接的操作功能,还有用户定义属性的存储功能,这点非常重要。IoSession 是线程安全的,也就是我们能够在多线程环境中随意操作 IoSession,这点给开发带来很大的好处。我们来看看具体提供的方法,笔者列举一些比较常用和重要的方法

在这里,笔者把 IoSession 的方法大致分成三类

第一类,连接操作功能。

最主要的方法有两个,向客户端发送消息和断开连接。可以看的出,write 接受的变量是一个 Object,但是实际上应该传入什么类型呢?具体还得看你是否使用了 ProtocolCodecFilter(下面会详细介绍),如果使用了 ProtocolCodecFilter,那这个 message 将可能是一个 String,或者是一个用户定义的 JavaBean。默认的情况,message 是一个 ByteBuffer。ByteBuffer 是 MINA 的一个类,跟 java.nio.ByteBuffer 类同名,MINA 2.0 将会将它改成 IoBuffer,以避免讨论上的误会。

另一个值得留意的是 Future 类,MINA 是一个非阻塞的通信框架,其中一个明显的体现就是调用 IoSession.write 方法是不会阻塞的。用户调用了 write 方法之后,消息内容会发到底层等候发送,至于什么时候发出,就不得而知了。当然,实际上调用了 write 之后,数据几乎是立刻发出的,这得益与 NIO 的高性能。但是,如果我们必须确认了消息发出,然后进行某些处理,我们就需要使用 Future 类,以下是一个很常见的代码。

通过调用 future.join,程序就会阻塞,直至消息处理结束。我们还能通过 future.isWritten 得知消息是否成功发送。

在这里,笔者顺便说一个实际使用的发现,消息发送是会自动合并的,简单来说,如果在很短的时间里,对同一个 IoSession 进行了两次 write 操作,客户端有可能只收到一条消息,而这条消息就是服务器发出的两条消息前后接起来。这样的设计可以在高并发的时候节省网络开销,而笔者的实际使用过程中,效果也相当好。但是如果这样行为会导致客户端工作不正常,你也可以通过参数关闭它。

第二类,属性存储操作。

通常来说,我们的系统是有用户状态的,我们就需要在连接上存储用户属性,IoSession 的 Attribute 就是这样一个功能。例如两个连接同时连入服务器,一个连接是用户 A,用户 ID 是 13,另一个连接是用户 B,用户 ID 是 14,我们就可以在用户登录成功之后,调用 IoSession.setAttribute(“login_id”,13),然后在其后的操作中,通过 IoSession.getAttribute(“login_id”)获得当前登录用户 ID,并进行相应的操作。简单来说,就是一个类似 HttpSession 的功能,当然具体的实现方法不一样。

第三类,连接状态。

这里就不多说了,从方法名上我们就能知道它具体的功能。

IoFilter

过滤器是 MINA 的一个很重要的功能。IoFilter 也是一个接口,但是相对比较复杂,这里就不列举它的方法了。简单来说 IoFilter 就像 ServletFilter,在事件被 IoHandler 处理之前或之后进行一些特定的操作,但是它比 ServletFilter 复杂,可以处理很多种事件,除了包括 IoHandler 的 7 个事件以外,还有一些内部的事件可以进行操作。

MINA 提供了一些常用的 IoFilter 实现,例如有 LoggingFilter(日志功能)、BlacklistFilter(黑名单功能)、CompressionFilter(压缩功能)、SSLFilter(SSL 支持),这些过滤器比较简单,通过阅读它们的源代码,能够更进一步理解过滤器的实现。笔者在这里要重点介绍两个过滤器,ProtocolCodecFilter 和 ExecutorFilter

ProtocolCodecFilter

网络传输的内容其实本质是一个二进制流,但是我们的业务功能不会,或者说不应该去直接操作二进制流。MINA 默认向 IoHandler 传入的 message 是一个 ByteBuffer,如果我们直接在 IoHandler 操作 ByteBuffer,会导致大量协议分析的代码和实际的业务代码混杂在一起。最适合的做法,就是在 IoFilter 把 ByteBuffer 转换成 String 或者 JavaBean,ProtocolCodecFilter 正是这样的一个功能的过滤器。

使用 ProtocolCodecFilter 很简单,我们只要把 ProtocolCodecFilter 加入到 FilterChain 就可以了,但是我们需要提供一个 ProtocolCodecFactory。其实 ProtocolCodecFilter 仅仅是实现了过滤器部分的功能,它会将最终的转换工作,交给从 ProtocolCodecFactory 获得的 Encode 和 Decode。如果我们需要编写自己的 ProtocolCodec,就应该从 ProtocolCodecFactory 入手。MINA 内置了几个 ProtocolCodecFactory,比较常用的就是 ObjectSerializationCodecFactory 和 TextLineCodecFactory。

ObjectSerializationCodecFactory 是 Java Object 序列化之后的内容直接跟 ByteBuffer 互相转化,比较适合两端都是 Java 的情况使用。TextLineCodecFactory 就是 String 跟 ByteBuffer 的转化,说白了就是文本,例如你要实现一个 SMTP 服务器,或者 POP 服务器,就可以使用它。而笔者的实际使用,大多数情况都是使用

TextLineCodecFactory

这里提及一下 IoFilter 的顺序问题,IoFilter 是有加入顺序的,例如,先加入 LoggingFilter 再加入 ProtocolCodecFilter,和先加入 ProtocolCodecFilter 再加入 LoggingFilter 的效果是不一样的,前者 LoggingFilter 写入日志的内容是 ByteBuffer,而后者写入日志的是转换后具体的

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • V2EX

    V2EX 是创意工作者们的社区。这里目前汇聚了超过 400,000 名主要来自互联网行业、游戏行业和媒体行业的创意工作者。V2EX 希望能够成为创意工作者们的生活和事业的一部分。

    17 引用 • 236 回帖 • 298 关注
  • PWL

    组织简介

    用爱发电 (Programming With Love) 是一个以开源精神为核心的民间开源爱好者技术组织,“用爱发电”象征开源与贡献精神,加入组织,代表你将遵守组织的“个人开源爱好者”的各项条款。申请加入:用爱发电组织邀请帖
    用爱发电组织官网:https://programmingwithlove.stackoverflow.wiki/

    用爱发电组织的核心驱动力:

    • 遵守开源守则,体现开源&贡献精神:以分享为目的,拒绝非法牟利。
    • 自我保护:使用适当的 License 保护自己的原创作品。
    • 尊重他人:不以各种理由、各种漏洞进行未经允许的抄袭、散播、洩露;以礼相待,尊重所有对社区做出贡献的开发者;通过他人的分享习得知识,要留下足迹,表示感谢。
    • 热爱编程、热爱学习:加入组织,热爱编程是首当其要的。我们欢迎热爱讨论、分享、提问的朋友,也同样欢迎默默成就的朋友。
    • 倾听:正确并恳切对待、处理问题与建议,及时修复开源项目的 Bug ,及时与反馈者沟通。不抬杠、不无视、不辱骂。
    • 平视:不诋毁、轻视、嘲讽其他开发者,主动提出建议、施以帮助,以和谐为本。只要他人肯努力,你也可能会被昔日小看的人所超越,所以请保持谦虚。
    • 乐观且活跃:你的努力决定了你的高度。不要放弃,多年后回头俯瞰,才会发现自己已经成就往日所仰望的水平。积极地将项目开源,帮助他人学习、改进,自己也会获得相应的提升、成就与成就感。
    1 引用 • 487 回帖 • 2 关注
  • Linux

    Linux 是一套免费使用和自由传播的类 Unix 操作系统,是一个基于 POSIX 和 Unix 的多用户、多任务、支持多线程和多 CPU 的操作系统。它能运行主要的 Unix 工具软件、应用程序和网络协议,并支持 32 位和 64 位硬件。Linux 继承了 Unix 以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统。

    948 引用 • 943 回帖
  • 尊园地产

    昆明尊园房地产经纪有限公司,即:Kunming Zunyuan Property Agency Company Limited(简称“尊园地产”)于 2007 年 6 月开始筹备,2007 年 8 月 18 日正式成立,注册资本 200 万元,公司性质为股份经纪有限公司,主营业务为:代租、代售、代办产权过户、办理银行按揭、担保、抵押、评估等。

    1 引用 • 22 回帖 • 779 关注
  • JVM

    JVM(Java Virtual Machine)Java 虚拟机是一个微型操作系统,有自己的硬件构架体系,还有相应的指令系统。能够识别 Java 独特的 .class 文件(字节码),能够将这些文件中的信息读取出来,使得 Java 程序只需要生成 Java 虚拟机上的字节码后就能在不同操作系统平台上进行运行。

    180 引用 • 120 回帖 • 2 关注
  • 运维

    互联网运维工作,以服务为中心,以稳定、安全、高效为三个基本点,确保公司的互联网业务能够 7×24 小时为用户提供高质量的服务。

    150 引用 • 257 回帖
  • Windows

    Microsoft Windows 是美国微软公司研发的一套操作系统,它问世于 1985 年,起初仅仅是 Microsoft-DOS 模拟环境,后续的系统版本由于微软不断的更新升级,不但易用,也慢慢的成为家家户户人们最喜爱的操作系统。

    223 引用 • 474 回帖
  • 支付宝

    支付宝是全球领先的独立第三方支付平台,致力于为广大用户提供安全快速的电子支付/网上支付/安全支付/手机支付体验,及转账收款/水电煤缴费/信用卡还款/AA 收款等生活服务应用。

    29 引用 • 347 回帖
  • Latke

    Latke 是一款以 JSON 为主的 Java Web 框架。

    71 引用 • 535 回帖 • 800 关注
  • Word
    13 引用 • 40 回帖
  • 印象笔记
    3 引用 • 16 回帖
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3192 引用 • 8214 回帖
  • 黑曜石

    黑曜石是一款强大的知识库工具,支持本地 Markdown 文件编辑,支持双向链接和关系图。

    A second brain, for you, forever.

    17 引用 • 162 回帖
  • 开源中国

    开源中国是目前中国最大的开源技术社区。传播开源的理念,推广开源项目,为 IT 开发者提供了一个发现、使用、并交流开源技术的平台。目前开源中国社区已收录超过两万款开源软件。

    7 引用 • 86 回帖
  • 服务器

    服务器,也称伺服器,是提供计算服务的设备。由于服务器需要响应服务请求,并进行处理,因此一般来说服务器应具备承担服务并且保障服务的能力。

    127 引用 • 589 回帖 • 1 关注
  • Love2D

    Love2D 是一个开源的, 跨平台的 2D 游戏引擎。使用纯 Lua 脚本来进行游戏开发。目前支持的平台有 Windows, Mac OS X, Linux, Android 和 iOS。

    14 引用 • 53 回帖 • 548 关注
  • 房星科技

    房星网,我们不和没有钱的程序员谈理想,我们要让程序员又有理想又有钱。我们有雄厚的房地产行业线下资源,遍布昆明全城的 100 家门店、四千地产经纪人是我们坚实的后盾。

    6 引用 • 141 回帖 • 584 关注
  • 面试

    面试造航母,上班拧螺丝。多面试,少加班。

    325 引用 • 1395 回帖 • 1 关注
  • 持续集成

    持续集成(Continuous Integration)是一种软件开发实践,即团队开发成员经常集成他们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。

    15 引用 • 7 回帖
  • Gitea

    Gitea 是一个开源社区驱动的轻量级代码托管解决方案,后端采用 Go 编写,采用 MIT 许可证。

    4 引用 • 16 回帖
  • ZeroNet

    ZeroNet 是一个基于比特币加密技术和 BT 网络技术的去中心化的、开放开源的网络和交流系统。

    1 引用 • 21 回帖 • 632 关注
  • CongSec

    本标签主要用于分享网络空间安全专业的学习笔记

    1 引用 • 1 回帖 • 18 关注
  • Gzip

    gzip (GNU zip)是 GNU 自由软件的文件压缩程序。我们在 Linux 中经常会用到后缀为 .gz 的文件,它们就是 Gzip 格式的。现今已经成为互联网上使用非常普遍的一种数据压缩格式,或者说一种文件格式。

    9 引用 • 12 回帖 • 162 关注
  • BookxNote

    BookxNote 是一款全新的电子书学习工具,助力您的学习与思考,让您的大脑更高效的记忆。

    笔记整理交给我,一心只读圣贤书。

    1 引用 • 1 回帖
  • 笔记

    好记性不如烂笔头。

    311 引用 • 796 回帖
  • 自由行
  • Visio
    1 引用 • 2 回帖