`
lingyibin
  • 浏览: 196833 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

Mina框架学习笔记(四)

阅读更多

上一节中给出了一个简单的基于 Apache MINA 的网络应用的实现,可以用来熟悉基本的架构。而在实际开发中,网络应用都是有一定复杂度的。下面会以一个比较复杂的联机游戏作为示例来详细介绍 Apache MINA 的概念、API 和典型用法。

该联机游戏支持两个人进行俄罗斯方块的对战。这个游戏借鉴了 QQ 的“火拼俄罗斯”。用户在启动客户端之后,需要输入一个昵称进行注册。用户可以在“游戏大厅”中查看当前已注册的所有其它用户。当前用户可以选择另外的一个用户发送游戏邀请。邀请被接受之后就可以开始进行对战。在游戏过程中,当前用户可以看到对方的游戏状态,即方块的情况。该游戏的运行效果如 图 3 所示。



联机游戏示例运行效果图 

下面开始以这个应用为例来具体介绍 Apache MINA 中的基本概念。先从 I/O 服务开始。




回页首

I/O 服务用来执行真正的 I/O 操作,以及管理 I/O 会话。根据所使用的数据传输方式的不同,有不同的 I/O 服务的实现。由于 I/O 服务执行的是输入和输出两种操作,实际上有两种具体的子类型。一种称为“I/O 接受器(I/O acceptor)”,用来接受连接,一般用在服务器的实现中;另外一种称为“I/O 连接器(I/O connector)”,用来发起连接,一般用在客户端的实现中。对应在 Apache MINA 中的实现,org.apache.mina.core.service.IoService是 I/O 服务的接口,而继承自它的接口org.apache.mina.core.service.IoAcceptor 和 org.apache.mina.core.service.IoConnector 则分别表示 I/O 接受器和 I/O 连接器。IoService 接口提供的重要方法如 表 1 所示。


方法 说明
setHandler(IoHandler handler) 设置 I/O 处理器。该 I/O 处理器会负责处理该 I/O 服务所管理的所有 I/O 会话产生的 I/O 事件。
getFilterChain() 获取 I/O 过滤器链,可以对 I/O 过滤器进行管理,包括添加和删除 I/O 过滤器。
getManagedSessions() 获取该 I/O 服务所管理的 I/O 会话。

下面具体介绍 I/O 接受器和 I/O 连接器。

I/O 接受器用来接受连接,与对等体(客户端)进行通讯,并发出相应的 I/O 事件交给 I/O 处理器来处理。使用 I/O 接受器的时候,只需要调用 bind方法并指定要监听的套接字地址。当不再接受连接的时候,调用 unbind停止监听即可。关于 I/O 接受器的具体用法,可以参考 清单 2 中给出的计算器服务的实现。

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

清单 3 中给出了使用 I/O 连接器的一个示例。


SocketConnector connector = new NioSocketConnector(); 
connector.setConnectTimeoutMillis(CONNECT_TIMEOUT); 
connector.getFilterChain().addLast("logger", new LoggingFilter()); 
connector.getFilterChain().addLast("protocol", 
    new ProtocolCodecFilter(new TetrisCodecFactory())); 
ConnectFuture connectFuture = connector.connect(new InetSocketAddress(host, port)); 
connectFuture.awaitUninterruptibly(); 

在 清单 3 中,首先创建一个 Java NIO 的套接字连接器 NioSocketConnector 的实例,接着设置超时时间。再添加了 I/O 过滤器之后,通过 connect 方法连接到指定的地址和端口即可。

在介绍完 I/O 服务之后,下面介绍 I/O 会话。




回页首

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

Apache MINA 中 I/O 会话实现的接口是 org.apache.mina.core.session.IoSession。该接口中比较重要的方法如 表 2 所示。


方法 说明
close(boolean immediately) 关闭当前连接。如果参数 immediately为 true的话,连接会等到队列中所有的数据发送请求都完成之后才关闭;否则的话就立即关闭。
getAttribute(Object key) 从 I/O 会话中获取键为 key的用户自定义的属性。
setAttribute(Object key, Object value) 将键为 key,值为 value的用户自定义的属性存储到 I/O 会话中。
removeAttribute(Object key) 从 I/O 会话中删除键为 key的用户自定义的属性。
write(Object message) 将消息对象 message发送到当前连接的对等体。该方法是异步的,当消息被真正发送到对等体的时候,IoHandler.messageSent(IoSession,Object)会被调用。如果需要的话,也可以等消息真正发送出去之后再继续执行后续操作。

在介绍完 I/O 会话之后,下面介绍 I/O 过滤器。




回页首

从 I/O 服务发送过来的所有 I/O 事件和请求,在到达 I/O 处理器之前,会先由 I/O 过滤器链中的 I/O 过滤器进行处理。Apache MINA 中的过滤器与 Servlet 规范中的过滤器是类似的。过滤器可以在很多情况下使用,比如记录日志、性能分析、访问控制、负载均衡和消息转换等。过滤器非常适合满足网络应用中各种横切的非功能性需求。在一个基于 Apache MINA 的网络应用中,一般存在多个过滤器。这些过滤器互相串联,形成链条,称为过滤器链。每个过滤器依次对传入的 I/O 事件进行处理。当前过滤器完成处理之后,由过滤器链中的下一个过滤器继续处理。当前过滤器也可以不调用下一个过滤器,而提前结束,这样 I/O 事件就不会继续往后传递。比如负责用户认证的过滤器,如果遇到未认证的对等体发出的 I/O 事件,则会直接关闭连接。这可以保证这些事件不会通过此过滤器到达 I/O 处理器。

Apache MINA 中 I/O 过滤器都实现 org.apache.mina.core.filterchain.IoFilter接口。一般来说,不需要完整实现 IOFilter接口,只需要继承 Apache MINA 提供的适配器 org.apache.mina.core.filterchain.IoFilterAdapter,并覆写所需的事件过滤方法即可,其它方法的默认实现是不做任何处理,而直接把事件转发到下一个过滤器。

IoFilter接口提供了 15 个方法。这 15 个方法大致分成两类,一类是与过滤器的生命周期相关的,另外一类是用来过滤 I/O 事件的。第一类方法如 表 3 所示。


方法 说明
init() 当过滤器第一次被添加到过滤器链中的时候,此方法被调用。用来完成过滤器的初始化工作。
onPreAdd(IoFilterChain parent, String name, IoFilter.NextFilter nextFilter) 当过滤器即将被添加到过滤器链中的时候,此方法被调用。
onPostAdd(IoFilterChain parent, String name, IoFilter.NextFilter nextFilter) 当过滤器已经被添加到过滤器链中之后,此方法被调用。
onPreRemove(IoFilterChain parent, String name, IoFilter.NextFilter nextFilter) 当过滤器即将被从过滤器链中删除的时候,此方法被调用。
onPostRemove(IoFilterChain parent, String name, IoFilter.NextFilter nextFilter) 当过滤器已经被从过滤器链中删除的时候,此方法被调用。
destroy() 当过滤器不再需要的时候,它将被销毁,此方法被调用。

在 表 3 中给出的方法中,参数 parent 表示包含此过滤器的过滤器链,参数 name 表示过滤器的名称,参数 nextFilter 表示过滤器链中的下一个过滤器。

第二类方法如 表 4 所示。


方法 说明
filterClose(IoFilter.NextFilter nextFilter, IoSession session) 过滤对 IoSession的 close方法的调用。
filterWrite(IoFilter.NextFilter nextFilter, IoSession session, WriteRequest writeRequest) 过滤对 IoSession的 write方法的调用。
exceptionCaught(IoFilter.NextFilter nextFilter, IoSession session, Throwable cause) 过滤对 IoHandler的 exceptionCaught方法的调用。
messageReceived(IoFilter.NextFilter nextFilter, IoSession session, Object message) 过滤对 IoHandler的 messageReceived方法的调用。
messageSent(IoFilter.NextFilter nextFilter, IoSession session, WriteRequest writeRequest) 过滤对 IoHandler的 messageSent方法的调用。
sessionClosed(IoFilter.NextFilter nextFilter, IoSession session) 过滤对 IoHandler的 sessionClosed方法的调用。
sessionCreated(IoFilter.NextFilter nextFilter, IoSession session) 过滤对 IoHandler的 sessionCreated方法的调用。
sessionIdle(IoFilter.NextFilter nextFilter, IoSession session, IdleStatus status) 过滤对 IoHandler的 sessionIdle方法的调用。
sessionOpened(IoFilter.NextFilter nextFilter, IoSession session) 过滤对 IoHandler的 sessionOpened方法的调用。

对于 表 4 中给出的与 I/O 事件相关的方法,它们都有一个参数是 nextFilter,表示过滤器链中的下一个过滤器。如果当前过滤器完成处理之后,可以通过调用 nextFilter中的方法,把 I/O 事件传递到下一个过滤器。如果当前过滤器不调用 nextFilter 中的方法的话,该 I/O 事件就不能继续往后传递。另外一个共同的参数是 session,用来表示当前的 I/O 会话,可以用来发送消息给对等体。下面通过具体的实例来说明过滤器的实现。

BlacklistFilter是 Apache MINA 自带的一个过滤器实现,其功能是阻止来自特定地址的连接,即所谓的“黑名单”功能。BlacklistFilter继承自 IoFilterAdapter,并覆写了 IoHandler相关的方法。清单 4 中给出了部分实现。


public void messageReceived(NextFilter nextFilter, IoSession session, Object message) { 
    if (!isBlocked(session)) { 
        nextFilter.messageReceived(session, message); 
    } else { 
        blockSession(session); 
    } 
} 

private void blockSession(IoSession session) { 
    session.close(true); 
}

在 清单 4 中 messageReceived 方法的实现中,首先通过 isBlocked 来判断当前连接是否应该被阻止,如果不是的话,则通过 nextFilter.messageReceived 把该 I/O 事件传递到下一个过滤器;否则的话,则通过 blockSession 来阻止当前连接。

ProtocolCodecFilter 用来在字节流和消息对象之间互相转换。当该过滤器接收到字节流的时候,需要首先判断消息的边界,然后把表示一条消息的字节提取出来,通过一定的逻辑转换成消息对象,再把消息对象往后传递,交给 I/O 处理器来执行业务逻辑。这个过程称为“解码”。与“解码”对应的是“编码”过程。在“编码”的时候,过滤器接收到的是消息对象,通过与“解码”相反的逻辑,把消息对象转换成字节,并反向传递,交给 I/O 服务来执行 I/O 操作。

在“编码”和“解码”中的一个重要问题是如何在字节流中判断消息的边界。通常来说,有三种办法解决这个问题:

  • 使用固定长度的消息。这种方式实现起来比较简单,只需要每次读取特定数量的字节即可。
  • 使用固定长度的消息头来指明消息主体的长度。比如每个消息开始的 4 个字节的值表示了后面紧跟的消息主体的长度。只需要首先读取该长度,再读取指定数量的字节即可。
  • 使用分隔符。消息之间通过特定模式的分隔符来分隔。每次只要遇到该模式的字节,就表示到了一个消息的末尾。

具体到示例应用来说,客户端和服务器之间的通信协议比较复杂,有不同种类的消息。每种消息的格式都不相同,同类消息的内容也不尽相同。因此,使用固定长度的消息头来指明消息主体的长度就成了最好的选择。

示例应用中的每种消息主体由两部分组成,第一部分是固定长度的消息类别名称,第二部分是每种消息的主体内容。图 4 中给出了示例应用中一条完整的消息的结构。



示例应用中消息的结构 

AbstractTetrisCommand用来描述联机游戏示例应用中的消息。它是一个抽象类,是所有具体消息的基类。其具体实现如 清单 5 所示。


public abstract class AbstractTetrisCommand implements TetrisCommand { 	
    public abstract String getName(); 

    public abstract byte[] bodyToBytes() throws Exception; 
	
    public abstract void bodyFromBytes(byte[] bytes) throws Exception; 

    public byte[] toBytes() throws Exception { 
        byte[] body = bodyToBytes(); 
        int commandNameLength = Constants.COMMAND_NAME_LENGTH; 
        int len = commandNameLength + body.length; 
        byte[] bytes = new byte[len]; 
        String name = StringUtils.rightPad(getName(), commandNameLength, 
            Constants.COMMAND_NAME_PAD_CHAR); 
        name = name.substring(0, commandNameLength); 
        System.arraycopy(name.getBytes(), 0, bytes, 0, commandNameLength); 
        System.arraycopy(body, 0, bytes, commandNameLength, body.length); 
        return bytes; 
    } 
}

如 清单 5 所示,AbstractTetrisCommand 中定义了 3 个抽象方法:getNamebodyToBytes 和 bodyFromBytes,分别用来获取消息的名称、把消息的主体转换成字节数组和从字节数组中构建消息。bodyToBytes对应于前面提到的“编码”过程,而 bodyFromBytes对应于“解码”过程。每种具体的消息都应该实现这 3 个方法。AbstractTetrisCommand 中的方法 toBytes 封装了把消息的主体转换成字节数组的逻辑,在字节数组中,首先是长度固定为 Constants.COMMAND_NAME_LENGTH的消息类别名称,紧接着是每种消息特定的主体内容,由 bodyToBytes 方法来生成。

转自:https://www.ibm.com/developerworks/cn/java/j-lo-mina2/#code1

 

分享到:
评论

相关推荐

    MIna2.0学习笔记

    Apache Mina是一个高性能、异步事件驱动的网络应用程序框架,主要用在开发网络通信应用...通过深入理解IoService接口和IoHandler机制,以及掌握如何创建和管理连接,可以更好地利用Mina框架来满足各种网络应用的需求。

    Mina2.0学习笔记(修订版).

    Apache Mina是一个高性能、事件驱动的网络应用框架,主要用于简化开发服务器端的复杂性,尤其在处理TCP/IP、UDP和SSL/...通过不断实践和深入学习,开发者可以更好地掌握Mina框架,构建出高效、稳定和可维护的网络应用。

    mina2学习笔记

    ### Mina2学习笔记知识点概览 #### 一、Mina入门详解 ##### 第一步:下载使用的Jar包 - **mina-core-2.0.0-M1.jar**:这是Mina核心库,提供了NIO框架的基本功能。 - **slf4j-api-1.5.2.jar**:用于日志记录的高级...

    Mina2.0学习笔记(完整版).doc

    IoSession是Mina框架中的核心概念,代表了客户端与服务器之间的一个会话。它包含了诸如读写操作、会话状态、连接参数等一系列重要信息。开发者可以通过IoSession进行数据传输、设置会话属性、管理会话生命周期等操作...

    Mina2.0学习笔记(修订版)

    ### Mina2.0学习笔记核心知识点概览 #### 一、Mina入门与环境搭建 ...以上是对《Mina2.0学习笔记(修订版)》的核心知识点概括,希望能帮助读者快速了解Mina框架的关键技术和应用场景,为后续深入学习打下坚实基础。

    Apache mina2学习笔记DEMO

    在这个"Apache MINA2学习笔记DEMO"中,我们很可能会看到如何使用MINA来创建一个自定义协议的示例。自定义协议通常是为了满足特定应用的需求,例如高效的数据传输、安全性或者特定的编码格式。MINA允许开发者定义自己...

    Apache_Mina2.0学习笔记

    最近使用Mina开发一个Java的NIO服务端程序,因此也特意学习了Apache的这个Mina框架。 引言 1 一. Mina入门 2 第一步.下载使用的Jar包 2 第二步.工程创建配置 2 第三步.服务端程序 3 第四步.客户端程序 6 第五步.长...

    Mina2.0学习笔记

    ### Mina2.0学习笔记知识点汇总 #### 一、Mina简介 - **Mina定义**:Mina是Apache组织推出的一个网络应用框架,它能够帮助开发者构建高性能且易于扩展的网络应用程序。通过提供一个抽象的、事件驱动的异步API,Mina...

    Mina学习笔记

    Apache Mina是一个基于Java的网络通信框架,专为高性能、高可用性和可扩展性而设计。...在深入学习Mina的过程中,理解IoService及其子类的工作原理,以及如何结合IoHandler实现业务逻辑,对于掌握Mina框架至关重要。

    mina初步学习笔记

    ### Mina初步学习笔记知识点概览 #### 一、Mina简介及下载配置流程 **Mina**,全称**Multipurpose Infrastructure Networked Applications**,是Apache基金会开发的一个高性能网络应用框架,旨在帮助开发者构建高...

    mina学习笔记,记录所有API

    在MINA的学习笔记中,记录的所有API通常会包括以下几个核心部分: 1. **IoSession**: 这是MINA的核心接口,代表了客户端和服务器之间的连接。IoSession提供了读写数据、管理连接状态、获取会话属性等功能。例如,`...

    Mina2.0学习笔记(重点)

    ### Mina2.0 学习笔记(重点) #### 一、Mina入门 ##### 第一步:下载使用的Jar包 1. **Mina核心库**:登录Mina官网下载`mina2.0.1.zip`,解压后得到`mina-core-2.0.0-M1.jar`。 2. **日志框架SLF4J**:访问SLF4J...

    Apache_Mina2.0学习笔记(初版).doc

    Apache Mina是一个强大的开源网络应用框架,主要设计用于构建高性能、高可扩展性的网络应用程序。Mina通过提供一个抽象的、事件驱动的异步API,简化了基于Java NIO(Non-blocking Input/Output)的复杂编程,使得...

    Mina 学习笔记(入门)

    **Mina 学习笔记(入门)** Apache Mina 是一个高度可扩展的网络通信框架,主要用于构建高性能、高效率的服务器端应用。它提供了一种简单的方式来处理网络协议,如TCP/IP和UDP/IP,以及SSL/TLS加密的连接。在本学习...

    apache mina 学习笔记三(子项目FtpServer)

    在本学习笔记中,我们将专注于MINA的子项目——FtpServer,它是实现FTP服务器功能的一个模块。 FTP(File Transfer Protocol)是一种广泛使用的互联网协议,用于在不同主机之间传输文件。Apache MINA FtpServer提供...

    mina学习笔记

    《mina学习笔记》 Apache MINA(Multipurpose Infrastructure for Network Applications)是一个开源框架,主要设计用于简化网络应用程序的开发,尤其是TCP和UDP协议的应用。MINA 提供了一种与网络协议无关的API,...

Global site tag (gtag.js) - Google Analytics