Apache MINA(Multipurpose Infrastructure for Network Applications) ?Apache l织一个较新的目Q它为开发高性能和高可用性的|络应用E序提供了非怾利的框架。当前发行的 MINA 版本支持Z Java NIO 技术的 TCP/UDP 应用E序开发、串口通讯E序Q只在最新的预览版中提供Q,MINA 所支持的功能也在进一步的扩展中?/p>
? 前正在?MINA 的Y件包括有QApache Directory Project、AsyncWeb、AMQPQAdvanced Message Queuing ProtocolQ、RED5 ServerQMacromedia Flash Media RTMPQ、ObjectRADIUS、Openfire {等?/p>
本文通过一个简单的问候程?HelloServer 来介l?MINA 的基架构的同时演C如何用MINA 开发网l应用程序?/p>
![]() ![]() |
![]()
|
HelloServer started on port 8080 |
好了Q一切正常,恭喜你的W一个?MINA
开发的|络E序已经成功q行了?/p>
![]() ![]() |
![]()
|
在介l架构之前先认识几个接口Q?/p>
IoAccepter 相当于网l应用程序中的服务器?/p>
IoConnector 相当于客L
IoSession 当前客户端到服务器端的一个连接实?/p>
IoHandler 业务处理逻辑
IoFilter qo器用于悬接通讯层接口与业务层接?/p>
![]() ![]() |
![]()
|
下图?MINA
的架构图Q?/p>
?1QMINA 的架构图
? 图中的模块链中,IoService 便是应用E序的入口,相当于我们前面代码中?IoAccepterQIoAccepter 便是 IoService 的一个扩展接口。IoService 接口可以用来d多个 IoFilterQ这?IoFilter W合责Q链模式ƈ? IoProcessor U程负责调用。?IoAccepter ?ioService 接口的基上还提供l定某个通讯端口以及取消l定的接口。在上面的例子中Q我们是q样使用 IoAccepter 的:
IoAcceptor acceptor = new SocketAcceptor(); |
相当于我们用了 Socket 通讯方式作ؓ服务的接入,当前版本?MINA q提供了?SocketAccepter 外的Z数据报文通讯? DatagramAccepter 以及Z道通讯? VmPipeAccepter。另外还包括串口通讯接入方式Q目前基于串口通讯的接入方式已l在最新测试版?MINA 中提供。你也可以自行实? IoService 接口来用自q通讯方式?/p>
而在上图中最右端也就? IoHandlerQ这便是业务处理模块。相当于前面例子中的 HelloHandler cR在业务处理cM不需要去兛_实际的通讯l节Q只处理客L传输q来的信息即可。编?Handler cd是?MINA 开发网l应用程序的重心所在,相当?MINA 已经帮你处理了所有的通讯斚w的细节问题。ؓ了简?Handler c,MINA 提供? IoHandlerAdapter c,此类仅仅是实C IoHandler 接口Q但q不做Q何处理?/p>
一?IoHandler 接口中具有如下一些方法(摘自 MINA ?API 文档Q:
void exceptionCaught(IoSession session, Throwable cause) 当接口中其他Ҏ抛出异常未被捕获时触发此Ҏ |
void messageReceived(IoSession session, Object message) 当接收到客户端的h信息后触发此Ҏ. |
void messageSent(IoSession session, Object message) 当信息已l传送给客户端后触发此方? |
void sessionClosed(IoSession session) 当连接被关闭时触发,例如客户端程序意外退出等{? |
void sessionCreated(IoSession session) 当一个新客户端连接后触发此方? |
void sessionIdle(IoSession session, IdleStatus status) 当连接空闲时触发此方? |
void sessionOpened(IoSession session) 当连接后打开时触发此ҎQ一般此Ҏ?sessionCreated 会被同时触发 |
前面我们提到 IoService 是负责底层通讯接入Q?IoHandler 是负责业务处理的。那?MINA 架构图中?IoFilter 作何用途呢Q答案是你想作何用途都可以。但是有一个用途却是必ȝQ那是作ؓ IoService ?IoHandler 之间的桥梁。IoHandler 接口中最重要的一个方法是 messageReceivedQ这个方法的W二个参数是一?Object 型的消息QL周知QObject 是所?Java 对象的基Q那到底谁来军_q个消息到底是什么类型呢Q答案也在q个 IoFilter 中。在前面使用的例子中Q我们添加了一?IoFilter ?new ProtocolCodecFilter(new TextLineCodecFactory())Q这个过滤器的作用是来自客L输入的信息{换成一行行的文本后传递给 IoHandlerQ因此我们可以在 messageReceived 中直接将 msg 对象强制转换?String 对象?/p>
? 如果我们不提供Q何过滤器的话Q那么在 messageReceived Ҏ中的W二个参数类型就是一?byte 的缓冲区Q对应的cL org.apache.mina.common.ByteBuffer。虽然你也可以将解析客户端信息放?IoHandler 中来做,但这q不是推荐的做法Q原来清晰的模型又模糊hQ变?IoHandler 不只是业务处理,q得充当协议解析的Q务?/p>
MINA自n带有一些常用的qo器,例如LoggingFilterQ日志记录)、BlackListFilterQ黑名单qoQ、CompressionFilterQ压~)、SSLFilterQSSL加密Q等?/p>
![]() ![]() |
![]()
|
MINA 不仅仅是用来开发网l服务器端应用程序,它一样可以?IoConnector 来连接到各种各样的网l服务程序?/p>
? q本文中 HelloServer q个例子Q我们在惊叹 MINA 可以带来多么大便利的同时Q还不得不ؓ其卓的性能而骄Ԍ据称使用MINA开发服务器E序的性能已经D使用 C/C++ 语言开发的|络服务。作? MINA 的入门文章,性能问题不在本文讨论范围内?/p>
另外?MINA 压羃包中附带有不比 HelloServer 要好得多的例子,通过q些例子可以q一步的了解q掌?MINA?/p>
1。MINA 框架?/p>
当客户首ơ访问采用MINA~写的程序时QIoAcceptor作ؓU程q行Q负责接受来自客Lh。当有客戯求连接时Q创Z? SessionQ该Session与IoProcessor、SocketChannel以及IOService联系h。IoProcessor也作? 另外一个线E运行,定时查客h否有数据到来Qƈ对客戯求进行处理,依次调用在IOService注册的各个IoFilterQ最后调? IoHandlerq行最l的逻辑处理Q再处理后的结果Filter后返回给客户端?/p>
2。IoSession
Session可以理解为服务器与客L的特定连接,该连接由服务器地址、端口以及客L地址、端口来军_。客L发vhӞ指定服务器地址和端口,客户端也会指定或者根据网l\׃息自动指定一个地址、自动分配一个端口。这个地址、端口对构成一个Session?/p>
Session是服务器端对q种q接的抽象,MINA对其q行了封装,定义了IoSession接口Q用来代表客L与服务器的连接,在服务器端来 指代客户端,实现对客L的操作、绑定与客户端有关的信息与对象。通过利用Session的这个概念,~写E序时就可以在服务器端非常方便地区分出是当前 处理的是哪个客户端的h、维持客L的状态信息、可以实现客L之间怺通讯?/p>
IoSession提供以下一些常用方法:
Q?QsetAttribute(Object key, Object value) getAttribute(Object key)
讄/获取用户定义的属性?/p>
该属性与session联系hQ方便以后处理用戯求时使用。比如如果要求用L录后才能l箋q行操作Q那么在用户成功登陆后,可以通过 setAttribute()讄一个属性,当用户以后l请求时Q可以通过getAttribute()获取该属性来判断用户是否d?/p>
Q?QgetRemoteAddress()
获取q程客户端地址?/p>
Q?QgetId() getCreationTime() getLastIoTime() getConfig()
获取Session的Id、创建时间、上ơIO旉、配|信息?/p>
Q?Qwrite(Object message)
数据发送给客户端?/p>
Q?Qclose()
关闭Session?/p>
说明Q可以在Session中发送数据,但是Session没有提供d数据的方法,d数据通过另一套机制在IoHandler的messageReceived()中实现?/p>
3。Event
MINA可以看成是事仉动的。通常在网l通讯中,可以整个过E划分ؓ几个基本的阶D,如徏立连接、数据通信、关闭连接?/p>
数据通信一般包括数据的发送和接收Q由于在通信q程中,可能要多ơ发送和接收数据Q以q行不同的业务交互?/p>
不可能一直都接收和发送数据,因此有Idle出现Q在MINA中,如果在设定的旉内没有数据发送或接收Q那么就会触发一个Idle事g?/p>
׃某种原因Q可能会发生错误Q导致系l异常发生,引发exception?/p>
因此Q如果从事g发生的角度看的话Q就可以在MINA中将通信看成׃个徏立链接(sessionCreated ?sessionOpened Q、多个数据接收和发送、一个关闭连接事件以及多个Idle事g{?U事件组成的q程?/p>
Session是对双方怺通信的抽象,因此通信的过E就是一pd与Session相关的事件?/p>
在MINA现在对TCP的实CQsessionCreated ?sessionOpened 没有区别。因此严格来_?U类型的事g?/p>
4。IoHandler
从以上MINA框架囑֏以看出,Ҏ自客L数据最l处理是在IoHandler中处理的。IoHandler装了来自客L不同事g的处理, 如果Ҏ个事件感兴趣Q可以实现相应的ҎQ当该事件发生时QIoHandler中的Ҏ׃被触发执行。IoHandlerd?个方法对?个事 Ӟ
Q?Qvoid exceptionCaught(IoSession session, Throwable cause)
有异常发生时被触发?/p>
Q?Qvoid messageReceived(IoSession session, Object message)
有消息到达时被触发,message代表接收到的消息?/p>
Q?Qvoid messageSent(IoSession session, Object message)
发送消息时时被触发Q即在调用IoSession.write()时被触发Qmessage代表要发送的消息?/p>
Q?Qvoid sessionClosed(IoSession session)
当连接关闭时被触发,即Sessionl止时被触发?/p>
Q?Qvoid sessionCreated(IoSession session)
当创Z个新q接时被触发Q即当开始一个新的Session时被触发?/p>
Q?Qvoid sessionIdle(IoSession session, IdleStatus status)
当连接空闲时被触发。用IoSessionConfig中的setIdleTime(IdleStatus status, int idleTime)Ҏ可以讄session的空闲时间。如果该Session的空闲时间超q设|的|该方法被触发Q可以通过 session.getIdleCount(status)来获取sessionIdle被触发的ơ数?/p>
Q?Qvoid sessionOpened(IoSession session)
当打开一个连接时被触发。在目前的实CQ好?sessionOpened ?sessionCreated 没有太大区别QsessionCreated ?sessionOpened 之前被触发?/p>
IoHandler是一个接口,一般情冉|有必要直接实现该接口的每一个方法。MINA提供了一个IoHandlerAdapterc,该类实现? IoHandler要求的方法,但是都没有做M处理。当我们要编写自qHandlerӞ可以扩展IoHandlerAdapterQ重写我们关心的 事gҎ卛_。比如,一般情况,我们比较兛_是否接收到数据这个时_那么我们可以覆盖messageReceivedҎQ不用管其他Ҏ?/p>
5。IoFilter
IoFilter用来对客Lh或发送给客户的数据进行filter。与IoHandler一PFilter也是Z事g的,通过实现IoFilter接口Q就可以寚w信q程中的Session的事件进行处理?/p>
Filter是一U链式结构,与IoHandler不同Q处理每一USession事g的函CQ除了传入session对象外,q传入了 NextFilter对象Q用来代表下一个Filter。一般情况,在处理结束后Q调用下一个filter的相应方法作q一步处理。Filter也可以针 对特定的通信或数据,不进行进一步处理,可以不用调用NextFilter的相应方法?/p>
除了与Session相应?U事件外Q在IoFilter中还可以对Filter的init、destroy以及add、remove{时间爱女作出处理?/p>
MINA提供了一个IoFilterAdapterc,我们要编写自qFilterӞ可以扩展IoFilterAdapterQ不用直接实现IoFilter接口?/p>
Apache MINA提供一个LoggingFilterc,用来log通信q程?/p>