`
从百草园到三味书屋
  • 浏览: 52273 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

网络应用框架学习 之Mina篇

 
阅读更多
网络应用框架学习
之Mina篇

      Apache MINA 2 是一个开发高性能和高可伸缩性网络应用程序的网络应用框架。它提供了一个抽象的事件驱动的异步 API,可以使用 TCP/IP、UDP/IP、串口和虚拟机内部的管道等传输方式。Apache MINA 2 可以作为开发网络应用程序的一个良好基础。本文将介绍 Apache MINA 2 的基本概念和 API,包括 I/O 服务、I/O 会话、I/O 过滤器和 I/O 处理器。

1.体系结构
网络对等体-->I/O服务->过滤器练-->I/O处理器->过滤器连-->I/O服务-->网络对等体
其中,过滤器链为多个过滤器组成的链条。
2.I/O服务
      I/O 服务:I/O 服务用来执行实际的 I/O 操作,以及管理 I/O 会话。Apache MINA 已经提供了一系列支持不同协议的 I/O 服务,如 TCP/IP、UDP/IP、串口和虚拟机内部的管道等。例如:
  • 对于TCP/IP协议:SocketAcceptor,SocketConnector以及基于NIO的NIOSocketAcceptor等,
  • 对于UDP/IP协议:DatagramAcceptor,DatagramConnector以及基于NIO的NIODatagramConnector,NIODatagramAcceptor等。
  • 对于串口协议来讲,Mina2.x系列的API里面好像没有提供,在网上搜了一下,也有相关介绍,例如连接串口同样实现了IoConnector接口,如果手头上的Mina版本没有提供串口协议API,在访问串口之前,Java应用程序需要一个native库,请把它放到你的JDK或JRE的lib /i386/下,并在程序启动的命令行中加入-Djava.library.path=来指定你的native库的位置。
  • 虚拟机管道:VmPipeAcceptor,VmpipeConnector等。

    实质上,IO服务执行的就是两种操作:一种是输入,一种是输出;IO服务提供两种类型,一种是IO接受器(IoAcceptor),用来接收链接,一般在服务器端使用;另一种是连接器(IoConnector),用来发起连接,用在客户端。
3.I/O会话

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

其中比较重要的方法有:
[code=“java”]
/**关闭当前连接。如果参数immediately为true的话,连接会等到队列中所有的数据发送请求都完成之后才关闭;否则的话就立即关闭。
*/
CloseFuture close(boolean immediately);

/**从 I/O 会话中获取键为key的用户自定义的属性。**/
Object getAttribute(Object key);

/**将键为key,值为value的用户自定义的属性存储到 I/O 会话中。**/
Object setAttribute(Object key, Object value)

/**从 I/O 会话中删除键为key的用户自定义的属性。**/
Object removeAttribute(Object key);

/**将消息对象message发送到当前连接的对等体。该方法是异步的,当消息被真正发送到对等体的时候,IoHandler.messageSent(IoSession,Object)会被调用。如果需要的话,也可以等消息真正发送出去之后再继续执行后续操作。
**/
WriteFuture write(Object message);


4.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,这个接口定义了大量的操作,一般来讲,普通应用中,不需要全部实现该接口所提供的方法,为了简便起见,Mian提供了一个适器:org.apache.mina.filterChain.IoFilterAdapter,我们只要继承该适配器就行了。
IoFilter接口中的与Filter生命周期相关的重要函数如下
/**当过滤器第一次被添加到过滤器链中的时候,此方法被调用。用来完成过滤器的初始化工作。
**/
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()

IoFilter中,过滤I/O事件的方法如下
/**过滤对IoSession的close方法的调用。**/
filterClose(IoFilter.NextFilter nextFilter, IoSession session)

/**过滤对IoSession的write方法的调用。**/
filterWrite(IoFilter.NextFilter nextFilter, IoSession session, WriteRequest writeRequest)

/**过滤对IoHandler的exceptionCaught方法的调用。**/
exceptionCaught(IoFilter.NextFilter nextFilter, IoSession session, Throwable cause)

/**过滤对IoHandler的messageReceived方法的调用。**/
messageReceived(IoFilter.NextFilter nextFilter, IoSession session, Object message)

/**过滤对IoHandler的messageSent方法的调用。**/
messageSent(IoFilter.NextFilter nextFilter, IoSession session, WriteRequest writeRequest)

/**过滤对IoHandler的sessionClosed方法的调用。**/
sessionClosed(IoFilter.NextFilter nextFilter, IoSession session)

/**过滤对IoHandler的sessionCreated方法的调用。**/
sessionCreated(IoFilter.NextFilter nextFilter, IoSession session)

/**过滤对IoHandler的sessionIdle方法的调用。**/
sessionIdle(IoFilter.NextFilter nextFilter, IoSession session, IdleStatus status)


/**过滤对IoHandler的sessionOpened方法的调用。**/
sessionOpened(IoFilter.NextFilter nextFilter, IoSession session)


      我们在写I/O过滤器的时候,一般不会直接实现IoFilter,也很少去直接继承其适配器
而是通过继承ProtocolCodecFactory来给字节或者某种特殊协议转换成消息对象的时候提供解码和编码服务,然后再通过ProtocolCodecFilter封装成IoFilter。因为因为TCP协议保证所有的包按顺序送达,但它不保证发送方的写操作与接受方的读操作一一对应。具体到MINA中,在不使用ProtocolCodecFilter的情况下,发送方一次调用IoSession.write(Object message) 有可能多次触发接受方的messageReceived(IoSession session, Object message) 事件,也有可能发送方多次调用IoSession.write(Object message),而接受方只触发一次 messageReceived(IoSession session, Object message)事件,当你的客户端和服务端运行在同一台机器上或者运行在同一个子网的时候,你可能不会遇到这个问题,但是你的应用应该支持这种情况。你也可以在IoHandler实现这些逻辑,但是使用ProtocolCodecFilter可以让你的代码更干净也更容易理解。下面是网上摘录的一段关于PortocolCodecFilter的介绍:
   
引用
  ProtocolCodecFilter用来在字节流和消息对象之间互相转换。当该过滤器接收到字节流的时候,需要首先判断消息的边界,然后把表示一条消息的字节提取出来,通过一定的逻辑转换成消息对象,再把消息对象往后传递,交给 I/O 处理器来执行业务逻辑。这个过程称为“解码”。与“解码”对应的是“编码”过程。在“编码”的时候,过滤器接收到的是消息对象,通过与“解码”相反的逻辑,把消息对象转换成字节,并反向传递,交给 I/O 服务来执行 I/O 操作。

5.I/O处理器
    I/O 事件通过过滤器链之后会到达 I/O 处理器。I/O 处理器中与 I/O 事件对应的方法会被调用。Apache MINA 中org.apache.mina.core.service.IoHandler是 I/O 处理器要实现的接口,一般情况下,只需要继承自org.apache.mina.core.service.IoHandlerAdapter并覆写所需方法即可。IoHandler接口的方法如下所示。
/**当有新的连接建立的时候,该方法被调用。**/
sessionCreated(IoSession session)

/**当有新的连接打开的时候,该方法被调用。该方法在sessionCreated之后被调用。**/
sessionOpened(IoSession session)

/**当连接被关闭的时候,此方法被调用。**/
sessionClosed(IoSession session)

/**当连接变成闲置状态的时候,此方法被调用。**/
sessionIdle(IoSession session, IdleStatus status)

/**当 I/O 处理器的实现或是 Apache MINA 中有异常抛出的时候,此方法被调用。**/
exceptionCaught(IoSession session, Throwable cause)

/**当接收到新的消息的时候,此方法被调用。**/
messageReceived(IoSession session, Object message)

/**当消息被成功发送出去的时候,此方法被调用。**/
messageSent(IoSession session, Object message)


   有几个需要重点的说明一下。首先是sessionCreated和sessionOpened的区别。sessionCreated方法是由 I/O 处理线程来调用的,而sessionOpened是由其它线程来调用的。因此从性能方面考虑,不要在sessionCreated方法中执行过多的操作。对于sessionIdle,默认情况下,闲置时间设置是禁用的,也就是说sessionIdle并不会被调用。可以通过IoSessionConfig.setIdleTime(IdleStatus, int)来进行设置。
6.例子

下面这个例子是模拟客户端和服务器端通信的例子。
•客户端程序
•I/O过滤器

package mina.client;


import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFactory;
import org.apache.mina.filter.codec.ProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolEncoder;

/**
 *
 * @author  meiquan_yang
 * @since   java 1.0.0
 * @created 2012-5-30
 */

public class MyFilter implements ProtocolCodecFactory {
	private ProtocolEncoder encoder = new MyEncoder();
	private ProtocolDecoder decoder = new MyDecoder();

	@Override
	public ProtocolEncoder getEncoder(IoSession session) throws Exception {
		return encoder;
	}


	@Override
	public ProtocolDecoder getDecoder(IoSession session) throws Exception {
		
		return decoder;
	}

}

•解码 协议数据->消息对象
package mina.client;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;

/**
 *
 * @author  meiquan_yang
 * @since   java 1.0.0
 * @created 2012-5-30
 */

public class MyDecoder implements ProtocolDecoder {


	@Override
	public void decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out)
			throws Exception {
		byte[] b = new byte[in.remaining()];
		in.get(b);
		/**接收到的原始数据进行处理,例如确定边界、数据过滤等**/
		
		/**如果下面还有过滤器,则继续过滤数据,否则调用处理器的MessageRecived方法,则write**/
		out.write(IoBuffer.wrap(b));
	}

	@Override
	public void finishDecode(IoSession session, ProtocolDecoderOutput out)
			throws Exception {

	}

	
	@Override
	public void dispose(IoSession session) throws Exception {

	}

} 

•编码 消息对象->二进制/协议 数据
package mina.client;

import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoder;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;

/**
 *
 * @author  meiquan_yang
 * @since   java 1.0.0
 * @created 2012-5-30
 */

public class MyEncoder implements ProtocolEncoder {

	
	@Override
	public void dispose(IoSession session) throws Exception {

	}


	@Override
	public void encode(IoSession session, Object message,
			ProtocolEncoderOutput out) throws Exception {
		session.write(message);
	}

} 


•I/O处理器
package mina.client;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;

/**
 *
 * @author  meiquan_yang
 * @since   java 1.0.0
 * @created 2012-5-30
 */

public class IoHandler extends IoHandlerAdapter {

	@Override
	public void sessionCreated(IoSession session) throws Exception {
		super.sessionCreated(session);
	}

	@Override
	public void sessionClosed(IoSession session) throws Exception {
		super.sessionClosed(session);
	}

	@Override
	public void messageReceived(IoSession session, Object message)
			throws Exception {
		/***对数据进行处理,转换成想要的数据格式**/
		IoBuffer ib = (IoBuffer)message;
		byte[] b = new byte[ib.remaining()];
		ib.get(b);
		System.out.println("接收到"+session.getServiceAddress()+"发过来的数据:"+new String(b));
		/*************************************/
	}

	@Override
	public void messageSent(IoSession session, Object message) throws Exception {
	}

	@Override
	public void sessionOpened(IoSession session) throws Exception {
	}

}

•启动客户端
package mina.client;

import java.net.InetSocketAddress;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.transport.socket.nio.NioSocketConnector;


/**
 *
 * @author  meiquan_yang
 * @since   java 1.0.0
 * @created 2012-5-30
 */

public class Client {

	public static void main(String[] args) throws Exception{
		NioSocketConnector connector = new NioSocketConnector();
               //可增加多个过滤器对原始数据进行过滤
		connector.getFilterChain().addLast("myFilter", new ProtocolCodecFilter(new MyFilter()));
		IoHandler handler = new IoHandler();
		connector.setHandler(handler);
		connector.setConnectTimeoutMillis(3000);
		ConnectFuture future =connector.connect(new InetSocketAddress("172.19.4.157",9910));
		future.awaitUninterruptibly();
		final IoSession session = future.getSession();
		
		/**客户端每个3秒钟向服务端发送一次数据**/
		new Thread(new Runnable(){
			Integer i = 0;
			@Override
			public void run() {
				while(true){
					i++;
					try {
						Thread.sleep(3000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					String request = "%R1Q, 17017: 2"+i;
					session.write(IoBuffer.wrap(request.getBytes()));
				}
			}
		}).start();
		
	}
}


•服务端程序流程与之类似,在这里省略。具体可以看附件
•程序运行结果:
服务端:
session created!
session opened!
one decoder...
/172.19.4.157:3078客户端发过来的数据为:%R1Q, 17017: 21
one decoder...
/172.19.4.157:3078客户端发过来的数据为:%R1Q, 17017: 22
one decoder...
/172.19.4.157:3078客户端发过来的数据为:%R1Q, 17017: 23
one decoder...
/172.19.4.157:3078客户端发过来的数据为:%R1Q, 17017: 24
one decoder...
/172.19.4.157:3078客户端发过来的数据为:%R1Q, 17017: 25
one decoder...
/172.19.4.157:3078客户端发过来的数据为:%R1Q, 17017: 26
one decoder...
/172.19.4.157:3078客户端发过来的数据为:%R1Q, 17017: 27
one decoder...
/172.19.4.157:3078客户端发过来的数据为:%R1Q, 17017: 28
one decoder...
/172.19.4.157:3078客户端发过来的数据为:%R1Q, 17017: 29
one decoder...
/172.19.4.157:3078客户端发过来的数据为:%R1Q, 17017: 210
one decoder...
/172.19.4.157:3078客户端发过来的数据为:%R1Q, 17017: 211
one decoder...
/172.19.4.157:3078客户端发过来的数据为:%R1Q, 17017: 212
one decoder...
/172.19.4.157:3078客户端发过来的数据为:%R1Q, 17017: 213
one decoder...
/172.19.4.157:3078客户端发过来的数据为:%R1Q, 17017: 214
。。。。
客户端:
接收到/172.19.4.157:9910发过来的数据:%R1P, 0, 0: 0, 11227735508245754,11350089140743085, 3172409690178598, 2
接收到/172.19.4.157:9910发过来的数据:%R1P, 0, 0: 0, 11227735508245754,11350089140743085, 3172409690178598, 2
接收到/172.19.4.157:9910发过来的数据:%R1P, 0, 0: 0, 11227735508245754,11350089140743085, 3172409690178598, 2
接收到/172.19.4.157:9910发过来的数据:%R1P, 0, 0: 0, 11227735508245754,11350089140743085, 3172409690178598, 2
接收到/172.19.4.157:9910发过来的数据:%R1P, 0, 0: 0, 11227735508245754,11350089140743085, 3172409690178598, 2
接收到/172.19.4.157:9910发过来的数据:%R1P, 0, 0: 0, 11227735508245754,11350089140743085, 3172409690178598, 2
接收到/172.19.4.157:9910发过来的数据:%R1P, 0, 0: 0, 11227735508245754,11350089140743085, 3172409690178598, 2
接收到/172.19.4.157:9910发过来的数据:%R1P, 0, 0: 0, 11227735508245754,11350089140743085, 3172409690178598, 2
接收到/172.19.4.157:9910发过来的数据:%R1P, 0, 0: 0, 11227735508245754,11350089140743085, 3172409690178598, 2
接收到/172.19.4.157:9910发过来的数据:%R1P, 0, 0: 0, 11227735508245754,11350089140743085, 3172409690178598, 2
接收到/172.19.4.157:9910发过来的数据:%R1P, 0, 0: 0, 11227735508245754,11350089140743085, 3172409690178598, 2
接收到/172.19.4.157:9910发过来的数据:%R1P, 0, 0: 0, 11227735508245754,11350089140743085, 3172409690178598, 2
接收到/172.19.4.157:9910发过来的数据:%R1P, 0, 0: 0, 11227735508245754,11350089140743085, 3172409690178598, 2
...


分享到:
评论

相关推荐

    Mina通信框架应用示例

    Mina通信框架,全称为Apache MINA,是一个高度可扩展的、基于Java的网络应用程序开发框架。MINA的名字来源于多语言(Multi-purpose Infrastructure for Network Applications),它提供了非阻塞I/O(Non-blocking I/...

    mina-core网络应用框架实例

    《mina-core网络应用框架实例详解》 Mina(Mini阿帕奇)是一个高性能、异步事件驱动的网络应用程序框架,主要用于构建服务器端的网络应用程序,如TCP和UDP通信、FTP、SMTP、HTTP等协议的服务器。它使得开发者可以...

    Java springboot 整合mina 框架,nio通讯基础教程,mina框架基础教程.zip

    学习Java NIO,你需要理解这些核心概念,并熟练运用它们来构建高性能的网络应用程序。 Mina框架是一个轻量级的网络通信框架,基于Java NIO构建,它简化了网络编程的复杂性,提供了高效的I/O处理能力。Mina支持多种...

    高性能网络架构Mina框架 下载

    Mina通过采用多线程模型和异步I/O技术来提高网络应用的并发处理能力,从而实现高吞吐量、低延迟的服务。 #### 二、Mina框架的特点 ##### 2.1 高性能与可扩展性 Mina采用了多线程异步处理机制,能够有效利用系统...

    MINA NIO 高性能异步并发网络通讯框架

    利用 Mina 可以高效地完成以下任务: <br>TCP/IP 和 UDP/IP 通讯 串口通讯 VM 间的管道通讯... 不过不管怎样,如果你在使用 Java 进行并发网络应用开发, Mina 绝对是一个值得推荐和学习的优秀工具!

    TestMINA.zip_DEMO_Mina框架_java mina_mina_mina java

    Apache MINA(Multipurpose Infrastructure for Network Applications)是一个高度可扩展且高性能的网络应用程序框架,主要用于简化网络服务的开发。MINA 提供了一种抽象层,让开发者可以专注于编写业务逻辑,而无需...

    mina框架资源包

    Mina框架,全称为Apache Mina,是一款基于Java开发的网络通信应用框架,它提供了一种简单而高性能的方式来构建网络服务,尤其在处理TCP/IP、UDP/IP以及SSL/TLS协议方面表现卓越。本资源包包含了实现Mina框架基础功能...

    mina2核心框架

    《MINA2核心框架:构建高性能网络应用》 MINA(Java Multithreaded Network Application Framework)是一个由Apache软件基金会开发的开源网络通信框架,主要应用于构建高性能、高可用性的网络服务。MINA2作为其最新...

    mina框架实例

    Apache MINA(Multipurpose Infrastructure for Network Applications)是一个高性能、异步事件驱动的网络应用程序框架,主要用于简化开发可扩展且高效的网络应用,如TCP/IP和UDP/IP服务器。MINA的目标是帮助开发者...

    Apache MINA框架相关资料

    Apache MINA(Multipurpose Infrastructure for Network Applications)是一个高性能、异步事件驱动的网络应用程序框架,主要用于简化开发高质量的网络服务。这个框架适用于多种协议,如TCP/IP和UDP/IP,以及NIO(非...

    java mina框架全套

    学习和使用Mina框架,可以帮助开发者快速构建稳定、高效的网络应用,降低网络编程的复杂度,同时充分利用Java NIO的优势。在实际项目中,结合Mina与其他开源库如Spring、Hibernate等,可以构建出更加强大的企业级...

    Mina框架入门介绍

    Apache Mina 框架是一个强大的网络通信框架,它的核心目标是简化开发高效且可扩展的网络应用程序。Mina 提供了基于事件驱动和异步IO的编程模型,特别是利用了Java NIO作为其默认的底层支持,这使得开发者能够构建高...

    Mina框架使用demo

    Mina框架是一个强大的网络应用开发框架,主要用于构建高性能、高可用性的网络服务器。在Java世界里,Mina因其异步事件驱动模型而受到广泛的青睐,它简化了TCP/IP和UDP协议编程,使得开发者可以专注于业务逻辑,而...

    mina框架demo

    学习MINA框架,你需要理解以下概念: - **Acceptor**:MINA中的Acceptor负责监听指定端口,接收并处理新的连接请求。 - **Session**:表示客户端和服务器之间的一个连接实例,包含了会话状态和相关的I/O操作。 - **...

    高性能Java网络框架 MINA.7z

    MINA(Multipurpose Infrastructure for Network Applications)是一个高性能、异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。MINA由Apache软件基金会开发,并且是其顶级项目之一...

    mina框架的demo 入门,开发

    Mina框架是一个基于Java的网络通信应用框架,它为高性能、高可用性的网络应用程序提供了强大的支持。本教程将深入探讨Mina框架的入门与开发,帮助你快速掌握这个框架的关键概念和技术。 首先,理解Mina的核心概念至...

    mina2框架+实例教程

    学习Mina2框架,可以通过阅读官方文档、参考教程和开源项目,理解其设计理念和使用方式。同时,深入研究提供的实例代码,有助于快速掌握Mina2的实际应用。 总结,Mina2作为一个强大的网络通信框架,为企业级的网络...

    Java学习之IO总结及mina和netty

    这篇博客“Java学习之IO总结及mina和netty”探讨了Java IO的基础知识,并深入到两个高级网络通信框架——Mina和Netty。Mina和Netty都是基于NIO(非阻塞IO)的高性能网络应用框架,它们简化了复杂网络编程的实现。 *...

    Mina通信框架应用

    **Mina通信框架应用** Apache Mina(Minimum Asynchronous Network Application framework)是一个开源的...通过学习和实践Mina通信框架,开发者可以更高效地构建高性能的网络应用,同时享受到Java生态的便利和强大。

Global site tag (gtag.js) - Google Analytics