文档章节

Mina系列文章

Echo_me
 Echo_me
发布于 2014/06/16 13:33
字数 2881
阅读 101
收藏 1
点赞 0
评论 0

Mina2简介   

     MINA2是一个网络通信应用框架,它主要用于基于TCP/IP、UDP/IP协议栈的通信框架,也可以提供 Java 对象的序列化服务、虚拟机管道通信服务等。MINA2可以帮助我们快速开发高性能、高扩展性的网络通信应用。MINA2 提供了事件驱动、异步(MINA2 的异步 IO 默认使用的是 Java NIO 作为底层支持)操作的编程模型。

Mina2在网络通信中的作用图

                

可见 MINA2 的 API 将真正的网络通信与我们的应用程序隔离开来,你只需要关心你要发送、接收的数据以及你的业务逻辑即可。同样的,无论是哪端,MINA2 的执行流程如下所示:

Mina2执行流程图

                    

或如下图:

MINA2 通信原理

异步 IO 模型

异步 I/O 模型大体上可以分为两种,反应式 (Reactive) 模型和前摄式 (Proactive) 模型:

1. 传统的 select / epoll / kqueue 模型,以及 Java NIO 模型,都是典型的反应式模型,即应用代码对 I/O 描述符进行注册,然后等待 I/O 事件。当某个或某些 I/O 描述符所对应的 I/O 设备上产生 I/O 事件(可读、可写、异常等)时,系统将发出通知,于是应用便有机会进行 I/O 操作并避免阻塞。由于在反应式模型中应用代码需要根据相应的事件类型采取不同的动作,最常见的结构便是嵌套的 if {...} else {...} 或 switch ,并常常需要结合状态机来完成复杂的逻辑。

2. 前摄式模型则不同。在前摄式模型中,应用代码主动地投递异步操作而不管 I/O 设备当前是否可读或可写。投递的异步 I/O 操作被系统接管,应用代码也并不阻塞在该操作上,而是指定一个回调函数并继续自己的应用逻辑。当该异步操作完成时,系统将发起通知并调用应用代码指定的回调函数。在前摄式模型中,程序逻辑由各个回调函数串联起来:异步操作 A 的回调发起异步操作 B ,B 的回调再发起异步操作 C ,以此往复。 MINA2 便是一个前摄式的异步 I/O 框架。

MINA2 基本概念

I/O服务:I/O 服务用来执行实际的 I/O 操作。MINA2 已经提供了一系列支持不同协议的 I/O 服务,如 TCP/IP、UDP/IP、串口和虚拟机内部的管道等。开发人员也可以实现自己的 I/O 服务。由于 I/O 服务执行的是输入和输出两种操作,实际上有两种具体的子类型。一种称为“I/O 接受器(I/O acceptor)”,用来接受连接,一般用在服务器的实现中;另外一种称为“I/O 连接器(I/O connector)”,用来发起连接,一般用在客户端的实现中。对应在 MINA2 中的实现,org.apache.mina.core.service.IoService 是 I/O 服务的接口,而继承自它的接口 org.apache.mina.core.service.IoAcceptor 和 org.apache.mina.core.service.IoConnector 则分别表示 I/O 接受器和 I/O 连接器。

I/O 接受器:I/O 接受器用来接受连接,与对等体(客户端)进行通讯,并发出相应的 I/O 事件交给 I/O 处理器来处理。使用 I/O 接受器的时候,只需要调用 bind 方法并指定要监听的套接字地址。当不再接受连接的时候,调用 unbind 停止监听即可。

I/O 连接器:I/O 连接器用来发起连接,与对等体(服务器)进行通讯,并发出相应的 I/O 事件交给 I/O 处理器来处理。使用 I/O 连接器的时候,只需要调用 connect 方法连接指定的套接字地址。另外可以通过 setConnectTimeoutMillis 设置连接超时时间(毫秒数)。

I/O 会话:I/O 会话表示一个活动的网络连接,与所使用的传输方式无关。I/O 会话可以用来存储用户自定义的与应用相关的属性。这些属性通常用来保存应用的状态信息,还可以用来在 I/O 过滤器和 I/O 处理器之间交换数据。I/O 会话在作用上类似于 Servlet 规范中的 HTTP 会话。

I/O过滤器:I/O 服务能够传输的是字节流,而上层应用需要的是特定的对象与数据结构。I/O 过滤器用来完成这两者之间的转换。I/O 过滤器的另外一个重要作用是对输入输出的数据进行处理,满足横切的需求。多个 I/O 过滤器串联起来,形成 I/O 过滤器链。Apache MINA 中的过滤器与 Servlet 规范中的过滤器是类似的。过滤器可以在很多情况下使用,比如记录日志、性能分析、访问控制、负载均衡和消息转换等。每个过滤器都可对通过的数据进行任意的操作,包括增加、删除、更新、类型转换等。先装上的过滤器更靠近远程端点 ( 客户端),后装上的更靠近本地端点 ( 服务器)。

I/O处理器:I/O 事件通过过滤器链之后会到达 I/O 处理器。I/O 处理器中与 I/O 事件对应的方法会被调用。MINA2 中 org.apache.mina.core.service.IoHandler 是 I/O 处理器要实现的接口,一般情况下,只需要继承自 org.apache.mina.core.service.IoHandlerAdapter 并覆写所需方法即可。

    MINA2 就是用来充当消息中间件解决各子系统之间通信的问题。在每个子系统增加 MINA2 的客户端和服务端,负责接收和发送 Mina 消息,调用其他子系统的业务功能和数据。

    在Mina2的源码中IoAcceptor及IoConnector都是IO服务IoService接口的实现,而此过程中的实现还包括了其他大量的接口及抽象类。I/O处理器、I/O过滤器及编码器都使用了适配器方式,分别是继承IoHandlerAdapter、IoFilter-Adapter、ProtocolEncoderAdapter,覆写所需方法。

Mina2提供的常见I/O过滤器有LoggingFilter(日志记录)、ProtocolCodecFilter(消息数据编解码)、BlacklistFilter("黑名单",阻止来自特定地址的连接)等。编码器需要实现ProtocolEncoder接口,一般继承ProtocolEncoderAdapter覆写所需方法即可,解码器一般继承CumulativeProtocolDecoder。

使用状态机

在 I/O 处理器中实现业务逻辑的时候,对于简单的情况,一般只需要在 messageReceived 方法中对传入的消息进行处理。如果需要写回数据到对等体的话,用 IoSession.write 方法即可。在另外的一些情况下,客户端和服务器端的通信协议比较复杂,客户端其实是有状态变迁的。这个时候可以用 Apache MINA 提供的状态机实现,可以使得 I/O 处理器的实现更加简单。

状态机中两个重要的元素是状态以及状态之间的迁移。

使用标注@state声明一个状态,使用标注@IoHandlerTransition声明一个状态迁移。

每个状态迁移可以有四个属性:on、in、next和 weight,其中属性 in是必须的,其余是可选的。属性 on表示触发此状态迁移的事件名称,如果省略该属性的话,则默认为匹配所有事件的通配符。该属性的值可以是表中给出的 I/O 处理器中能处理的七种事件类型。属性 in表示状态迁移的起始状态。属性 next表示状态迁移的结束状态,如果省略该属性的话,则默认为表示当前状态 的 _self_。属性 weight用来指明状态迁移的权重。一个状态的所有迁移是按照其权重升序排列的。对于当前状态,如果有多个可能的迁移,排序靠前的迁移将会发生。

如:@IoHandlerTransition(on = MESSAGE_RECEIVED, in = NOT_CONNECTED, next = IDLE) 

使用了 MINA 提供的状态机之后,创建 I/O 处理器的方式也发生了变化。I/O 处理器的实例由状态机来创建:

private static IoHandler createIoHandler() { 
    StateMachine sm = StateMachineFactory.getInstance( 
        IoHandlerTransition.class).create(ServerHandler.NOT_CONNECTED, 
        new ServerHandler()); 
    return new StateMachineProxyBuilder().setStateContextLookup( 
        new IoSessionStateContextLookup(new StateContextFactory() { 
            public StateContext create() { 
                return new ServerHandler.TetrisServerContext(); 
            } 
    })).create(IoHandler.class, sm); 
}

异步操作

MINA 中的很多操作都是异步的,比如连接的建立、连接的关闭、还有数据的发送等。在编写网络应用的时候,需要考虑这一点。比如 IoConnector的connect方法,其返回值是 org.apache.mina.core.future.ConnectFuture类的对象。通过此对象,可以查询连接操作的状态。另外一个常用的是发送数据时使用的 org.apache.mina.core.future.WriteFuture。

    IoConnector connector = new NioSocketConnector();
    connector.setConnectTimeoutMillis(3000);
        
    connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("utf-8"))));
    connector.getFilterChain().addLast("logger", new LoggingFilter());
        
    connector.setHandler(new TimeClientHandler());
        
    ConnectFuture future = connector.connect(new InetSocketAddress("127.0.0.1", PORT));
    future.awaitUninterruptibly();
    future.isConnected();
        
    IoSession session = future.getSession();
    WriteFuture writeFuture = session.write("what time is it now?");
    writeFuture.awaitUninterruptibly(); // 等待发送数据操作完成
    if(writeFuture.isWritten()){
       // 数据已经被成功发送 
    } else {
       // 数据发送失败
    }

JMX集成

MINA 可以集成 JMX 来对网络应用进行管理和监测。下面通过一简单示例来说明如何集成 JMX。

        IoAcceptor acceptor = new NioSocketAcceptor();
        // Mina与JMX的集成
        MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
        IoServiceMBean acceptorMBean = new IoServiceMBean(acceptor);
        ObjectName acceptorName = new ObjectName(acceptor.getClass().getPackage().getName()
                               + ":type=acceptor,name=" + acceptor.getClass().getSimpleName());
        mBeanServer.registerMBean(acceptorMBean, acceptorName);
        
        acceptor.getFilterChain().addLast("logger", new LoggingFilter());
        acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));
        acceptor.setHandler(new CalculatorHandler());
        acceptor.bind(new InetSocketAddress(PORT));

首先获取平台提供的受控 bean 的服务器,接着创建受控 bean(MBean)来包装想要管理和监测的对象,这里使用的是 I/O 接收器对象。最后把创建出来的受控 bean 注册到服务器即可。

在启动计算器服务应用的时候,添加下面的启动参数:-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=8084 -Dcom.sun.management.

jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false,就启用了 JMX。接着通过 JVM 提供的“Java 监视和管理控制台”(运行 jconsole)就可以连接到此应用进行管理和监测了。

Spring集成

MINA 可以和流行的开源框架 Spring 进行集成,由 Spring 来管理 MINA 中的对象。与 Spring 集成的方式也比较简单,只需要编写相应的 Spring 配置文件即可。

<?xml version="1.0" encoding="UTF-8"?> 
<beans> 
    <bean id="calculatorHandler" class="org.apache.mina.demo02.server.CalculatorHandler" /> 

    <bean id="loggingFilter" class="org.apache.mina.filter.logging.LoggingFilter" /> 

    <bean id="calculatorCodecFilter" class="org.apache.mina.filter. 
        codec.ProtocolCodecFilter"> 
        <constructor-arg> 
            <bean class="org.apache.mina.filter.codec.textline.TextLineCodecFactory" /> 
        </constructor-arg> 
    </bean> 

    <bean id="filterChainBuilder"
        class="org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder"> 
        <property name="filters"> 
            <map> 
                <entry key="loggingFilter" value-ref="loggingFilter" /> 
                <entry key="codecFilter" value-ref="calculatorCodecFilter" /> 
                </map> 
        </property> 
    </bean> 

    <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer"> 
        <property name="customEditors"> 
            <map> 
              <entry key="java.net.SocketAddress"> 
                <bean class="org.apache.mina.integration.beans.InetSocketAddressEditor"/> 
              </entry> 
            </map> 
        </property> 
    </bean> 

    <bean id="ioAcceptor" class="org.apache.mina.transport.socket.nio.NioSocketAcceptor"
        init-method="bind" destroy-method="unbind"> 
        <property name="defaultLocalAddress" value=":10010" /> 
        <property name="handler" ref="calculatorHandler" /> 
        <property name="filterChainBuilder" ref="filterChainBuilder" /> 
    </bean> 
</beans>

上面创建 I/O 处理器和 I/O 过滤器的方式很直接。由于不能直接从 I/O 接受器获取过滤器链,这里创建了一个 

org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder类的 bean,用来构建过滤器链。由 Apache MINA 

提供的网络地址编辑器 org.apache.mina.integration.beans.InetSocketAddressEditor允许以“主机名 : 端口”的形式

指定网络地址。在声明 I/O 接受器的时候,通过 init-method指明了当 I/O 接受器创建成功之后,调用其 bind方法来

接受连接;通过 destroy-method声明了当其被销毁的时候,调用其 unbind来停止监听。

更多Mina详细讲述及示例:

http://my.oschina.net/ielts0909/blog/92716

http://www.ibm.com/developerworks/cn/web/1108_sumeng_mina2/index.html 

http://www.ibm.com/developerworks/cn/java/j-lo-mina2/index.html 






© 著作权归作者所有

共有 人打赏支持
Echo_me
粉丝 34
博文 33
码字总数 46131
作品 0
海淀
高级程序员
NIO框架入门(三):iOS与MINA2、Netty4的跨平台UDP双向通信实战

前言 本文将演示一个iOS客户端程序,通过UDP协议与两个典型的NIO框架服务端,实现跨平台双向通信的完整Demo。服务端将分别用MINA2和Netty4进行实现,而通信时服务端你只需选其一就行了。同时...

JackJiang- ⋅ 2016/06/28 ⋅ 0

Mina系列文章索引

写了很多关于Apache Mina的文章,为了方便大家阅读,我将关于mina的一些文章做点儿索引。 Mina官网资料----------------------------------------------------------------- Mina官网是学习m...

Gaischen ⋅ 2012/11/28 ⋅ 15

网络编程懒人入门(五):快速理解为什么说UDP有时比TCP更有优势

本文观点仅作参考,请根据自已系统的应用场景合理地选择数据传输层协议即可,无需盲目崇拜大牛言论。 1、前言 对于即时通讯开者新手来说,在开始着手编写IM或消息推送系统的代码前,最头疼的...

JackJiang2011 ⋅ 2017/12/19 ⋅ 0

Android与MINA2、Netty4的跨平台UDP双向通信实战

概述 本文演示的是一个Android客户端程序,通过UDP协议与两个典型的NIO框架服务端,实现跨平台双向通信的完整Demo。 当前由于NIO框架的流行,使得开发大并发、高性能的互联网服务端成为可能。...

JackJiang- ⋅ 2016/06/30 ⋅ 1

NIO框架入门(二):服务端基于MINA2的UDP双向通信Demo演示

前言 NIO框架的流行,使得开发大并发、高性能的互联网服务端成为可能。这其中最流行的无非就是MINA和Netty了,MINA目前的主要版本是MINA2、而Netty的主要版本是Netty3和Netty4(Netty5已经被...

JackJiang- ⋅ 2016/06/24 ⋅ 0

Mina源码阅读笔记(七)—Mina的拦截器FilterChain

接上一篇《异步IO实现IoFuture》 Filter我们很熟悉,在Mina中,filter chain的用法也类似于Servlet的filters,这种拦截器的设计思想能够狠轻松的帮助我们实现对资源的统一处理。我们先大致连...

Gaischen ⋅ 2012/11/27 ⋅ 1

Netty那点事(一)概述

Netty和Mina是Java世界非常知名的通讯框架。它们都出自同一个作者,Mina诞生略早,属于Apache基金会,而Netty开始在Jboss名下,后来出来自立门户netty.io。关于Mina已有@FrankHui的Mina系列文...

黄亿华 ⋅ 2013/09/21 ⋅ 21

Mina源码阅读笔记(一)-整体解读

今天的这一节,将从整体上对mina的源代码进行把握,网上已经有好多关于mina源码的阅读笔记,但好多都是列举了一下每个接口或者类的方法。我倒是想从mina源码的结构和功能上对这个框架进行剖析...

Gaischen ⋅ 2012/11/19 ⋅ 19

基于mina实现一个简单数据采集中间件的多客户端在线测试程序

1、前言 之前的一篇文章介绍基于基于Mina实现的一个简单数据采集中间件的具体实现,该数据据采集中间件需要实现与多个终端的长连接,并定时给所有终端发送指令,终端在接收到相关指令后,返回...

ytangdigl ⋅ 2017/12/27 ⋅ 0

Mina源码阅读笔记(二)- IoBuffer的封装

上一篇《整体解读》的延续。。 在阅读IoBuffer源码之前,我们先看Mina对IoBuffer的描述:A byte buffer used by MINA applications. This is a replacement for ByteBuffer. 这是一个对ByteB...

Gaischen ⋅ 2012/11/20 ⋅ 16

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Centos7重置Mysql 8.0.1 root 密码

问题产生背景: 安装完 最新版的 mysql8.0.1后忘记了密码,向重置root密码;找了网上好多资料都不尽相同,根据自己的问题总结如下: 第一步:修改配置文件免密码登录mysql vim /etc/my.cnf 1...

豆花饭烧土豆 ⋅ 今天 ⋅ 0

熊掌号收录比例对于网站原创数据排名的影响[图]

从去年下半年开始,我在写博客了,因为我觉得业余写写博客也还是很不错的,但是从2017年下半年开始,百度已经推出了原创保护功能和熊掌号平台,为此,我也提交了不少以前的老数据,而这些历史...

原创小博客 ⋅ 今天 ⋅ 0

LVM讲解、磁盘故障小案例

LVM LVM就是动态卷管理,可以将多个硬盘和硬盘分区做成一个逻辑卷,并把这个逻辑卷作为一个整体来统一管理,动态对分区进行扩缩空间大小,安全快捷方便管理。 1.新建分区,更改类型为8e 即L...

蛋黄Yolks ⋅ 今天 ⋅ 0

Hadoop Yarn调度器的选择和使用

一、引言 Yarn在Hadoop的生态系统中担任了资源管理和任务调度的角色。在讨论其构造器之前先简单了解一下Yarn的架构。 上图是Yarn的基本架构,其中ResourceManager是整个架构的核心组件,它负...

p柯西 ⋅ 今天 ⋅ 0

uWSGI + Django @ Ubuntu

创建 Django App Project 创建后, 可以看到路径下有一个wsgi.py的问题 uWSGI运行 直接命令行运行 利用如下命令, 可直接访问 uwsgi --http :8080 --wsgi-file dj/wsgi.py 配置文件 & 运行 [u...

袁祾 ⋅ 今天 ⋅ 0

JVM堆的理解

在JVM中,我们经常提到的就是堆了,堆确实很重要,其实,除了堆之外,还有几个重要的模块,看下图: 大 多数情况下,我们并不需要关心JVM的底层,但是如果了解它的话,对于我们系统调优是非常...

不羁之后 ⋅ 昨天 ⋅ 0

推荐:并发情况下:Java HashMap 形成死循环的原因

在淘宝内网里看到同事发了贴说了一个CPU被100%的线上故障,并且这个事发生了很多次,原因是在Java语言在并发情况下使用HashMap造成Race Condition,从而导致死循环。这个事情我4、5年前也经历...

码代码的小司机 ⋅ 昨天 ⋅ 2

聊聊spring cloud gateway的RetryGatewayFilter

序 本文主要研究一下spring cloud gateway的RetryGatewayFilter GatewayAutoConfiguration spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/config/G......

go4it ⋅ 昨天 ⋅ 0

创建新用户和授予MySQL中的权限教程

导读 MySQL是一个开源数据库管理软件,可帮助用户存储,组织和以后检索数据。 它有多种选项来授予特定用户在表和数据库中的细微的权限 - 本教程将简要介绍一些选项。 如何创建新用户 在MySQL...

问题终结者 ⋅ 昨天 ⋅ 0

android -------- 颜色的半透明效果配置

最近有朋友问我 Android 背景颜色的半透明效果配置,我网上看资料,总结了一下, 开发中也是常常遇到的,所以来写篇博客 常用的颜色值格式有: RGB ARGB RRGGBB AARRGGBB 这4种 透明度 透明度...

切切歆语 ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部