mina学习笔记二:从官方例子开始

来源:互联网 发布:2016流行网络语言 编辑:程序博客网 时间:2024/06/16 02:12

       本节内容只介绍mina总体架构,同时给出官方的几个实用TCP、UDP的经典服务端客户端例子。


mina体系结构

    mina位于用户程序和网络处理之间,将用户从复杂的网络处理中解耦,那我们就可以更加关注业务领域。

图2.1 mina鸟瞰图

    让我们再深入进去,mina框架内部的各个组件是怎么协调工作的呢?
图2.2 mina组件结构图

    显然,mina框架被分成了主要的3个组件部分:
  • I/O Service,具体提供服务的组件。
  • I/O Filter Chain,过滤器链,用于支持各种切面服务。
  • I/O Handler,用于处理用户的业务逻辑。
    相对应的,为了创建一个基于mina的应用程序,我们需要:
  • 创建I/O Service :可选择mina提供的Services如(*Acceptor)或实现自己的Service。
  • 创建I/O Filter :同样可以选择mina提供的各类filter,也可以实现自己的编解码过滤器等。
  • 实现I/O Handler,实现Handler接口,处理各种消息。

服务端结构

    服务端的作用就是开启监听端口,等待请求的到来、处理他们、以及将发送对请求的响应。同时,服务端会为每个连接创建session,在session周期内提供各种精度的服务,比如连接创建时(sessionCreated(IoSession session))、连接等待时(sessionIdle(IoSession session, IdleStatus status))、连接销毁时(sessionClosed(IoSession session))等。mina的api为TCP/UDP提供的一致性Server端操作。

图2.3 Server结构图
  • IOAcceptor 监听来自网络的请求。
  • 当新的连接建立时,一个新的session会被创建,该session用作对同一IP/端口组合的客户端提供服务。
  • 数据包需经过一系列的过滤器,这些过滤器可用来修改数据包的内容(如转换对象、添加或修改信息等),其中将原始字节流转换成POJO对象是非常有用的。当然这需要解编码器提供支持。
  • 最后这些数据包或转化后的对象将交由IOHandler处理,我们将实现IOHandler用于处理具体的业务逻辑。

客户端结构

    客户端需要连接服务端,发送请求并处理响应。实际上客户端的结构和服务端极其相似。

图2.4 客户端结构
  • 客户端首先需要创建IOConnector对象,绑定服务端的IP和端口。
  • 一旦连接成功,一个于本次连接绑定的session对象将被创建。
  • 客户端发送给服务端的请求都需要经过一系列的fliter。
  • 同样,响应消息的接受也会经过一系列的filter再到IOHandler被处理。
    所以整体上,mina提供良好的一致性调用和封装结构。在使用mina创建基于网络的程序应用时,投入的学习成本比较低。

TCP连接的例子

    依赖的Jar包:
  • MINA 2.x Core
  • JDK 1.5 或以上
  • SLF4J 1.3.0 或以上
    • Log4J 1.2: slf4j-api.jar, slf4j-log4j12.jar, Log4j 1.2.x
    • Log4J 1.3: slf4j-api.jar, slf4j-log4j13.jar, Log4j 1.3.x(注意,请确认log4j的版本)
    TCP Server端代码:
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public class MinaTimeTest {  
  2.     private static final int PORT = 9123;  
  3.   
  4.     public static void main(String[] args) throws IOException {  
  5.         //首先,我们为服务端创建IoAcceptor,NioSocketAcceptor是基于NIO的服务端监听器  
  6.         IoAcceptor acceptor = new NioSocketAcceptor();  
  7.         //接着,如结构图示,在Acceptor和IoHandler之间将设置一系列的Fliter  
  8.         //包括记录过滤器和编解码过滤器。其中TextLineCodecFactory是mina自带的文本解编码器  
  9.         acceptor.getFilterChain().addLast("logger"new LoggingFilter());  
  10.         acceptor.getFilterChain().addLast("codec",  
  11.                 new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));  
  12.         //配置事务处理Handler,将请求转由TimeServerHandler处理。  
  13.         acceptor.setHandler(new TimeServerHandler());  
  14.         //配置Buffer的缓冲区大小  
  15.         acceptor.getSessionConfig().setReadBufferSize(2048);  
  16.         //设置等待时间,每隔IdleTime将调用一次handler.sessionIdle()方法  
  17.         acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);  
  18.         //绑定端口  
  19.         acceptor.bind(new InetSocketAddress(PORT));  
  20.     }  
  21.       
  22.     static class TimeServerHandler extends IoHandlerAdapter {  
  23.   
  24.         public void exceptionCaught(IoSession session, Throwable cause)  
  25.                 throws Exception {  
  26.             cause.printStackTrace();  
  27.         }  
  28.   
  29.         public void messageReceived(IoSession session, Object message)  
  30.                 throws Exception {  
  31.             String str = message.toString();  
  32.             if (str.trim().equalsIgnoreCase("quit")) {  
  33.                 session.close(false);  
  34.                 return;  
  35.             }  
  36.             Date date = new Date();  
  37.             session.write(date.toString());  
  38.             System.out.println("Message written...");  
  39.         }  
  40.           
  41.         public void sessionIdle(IoSession session, IdleStatus status)  
  42.                 throws Exception {  
  43.             System.out.println("IDLE " + session.getIdleCount(status));  
  44.         }  
  45.     }  
  46. }  



    TCP Client端代码:
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public class TimeClient {  
  2.     private static final String HOSTNAME = "127.0.0.1";  
  3.     private static final int PORT = 9123;  
  4.     private static final long CONNECT_TIMEOUT = 30 * 1000L; // 30 seconds  
  5.   
  6.     public static void main(String[] args) throws Throwable {  
  7.         //创建Connector连接器  
  8.         NioSocketConnector connector = new NioSocketConnector();  
  9.         //设置连接超时时间  
  10.         connector.setConnectTimeoutMillis(CONNECT_TIMEOUT);  
  11.           
  12.         connector.getFilterChain().addLast("codec",  
  13.                 new ProtocolCodecFilter(new TextLineCodecFactory()));  
  14.         connector.getFilterChain().addLast("logger"new LoggingFilter());  
  15.         //非常简单的处理Handler,向服务器发送一个数字  
  16.         connector.setHandler(new ClientSessionHandler(1));  
  17.         IoSession session = null;  
  18.   
  19.         try {  
  20.             //连接远程主机,设置IP和端口  
  21.             ConnectFuture future = connector.connect(new InetSocketAddress(  
  22.                     HOSTNAME, PORT));  
  23.             //等待连接建立  
  24.             future.awaitUninterruptibly();  
  25.             //连接建立后返回会话session  
  26.             session = future.getSession();  
  27.         } catch (RuntimeIoException e) {  
  28.             System.err.println("Failed to connect.");  
  29.             e.printStackTrace();  
  30.             Thread.sleep(5000);  
  31.         } finally{  
  32.             if(session!=null){  
  33.                 //等待本次连接通话结束,不可中断式的阻塞等待  
  34.                 session.getCloseFuture().awaitUninterruptibly();  
  35.             }  
  36.         }  
  37.         //关闭连接  
  38.         connector.dispose();  
  39.     }  
  40.     static class ClientSessionHandler extends IoHandlerAdapter {  
  41.         private final int value;  
  42.         public ClientSessionHandler(int value) {  
  43.             this.value = value;  
  44.         }  
  45.         @Override  
  46.         public void sessionOpened(IoSession session) {  
  47.             session.write(value);  
  48.         }  
  49.   
  50.         @Override  
  51.         public void messageReceived(IoSession session, Object message) {  
  52.             System.out.println(message);  
  53.             session.close(true);  
  54.         }  
  55.   
  56.         @Override  
  57.         public void exceptionCaught(IoSession session, Throwable cause) {  
  58.             session.close(true);  
  59.         }  
  60.     }  
  61. }  

UDP连接的例子

    UDP服务端:
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public class UdpServer {  
  2.     private final static int PORT = 9234;  
  3.     public static void main(String[] args) throws IOException {  
  4.         //创建UDPAcceptor  
  5.         NioDatagramAcceptor acceptor = new NioDatagramAcceptor(null);  
  6.         //这次不设置字符解编码器filter,消息直接用Buffer字节流传递  
  7.         acceptor.getFilterChain().addLast("logger"new LoggingFilter());  
  8.         acceptor.setHandler(new UDPHandler());  
  9.         acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);  
  10.         acceptor.getSessionConfig().setReuseAddress(true);//<span style="font-family: Arial, Helvetica, sans-serif;">NioDatagramAcceptor 设置为null,才能重复使用端口</span>  
  11.         acceptor.bind(new InetSocketAddress(PORT));  
  12.     }  
  13.     static class UDPHandler extends IoHandlerAdapter{  
  14.         @Override  
  15.         public void messageReceived(IoSession session, Object message)  
  16.                 throws Exception {  
  17.             IoBuffer buffer = (IoBuffer)message;  
  18.             System.out.println(buffer.getLong());  
  19.             session.close(false);  
  20.         }  
  21.         @Override  
  22.         public void sessionIdle(IoSession session, IdleStatus status)  
  23.                 throws Exception {  
  24.             System.out.println("IDLE " + session.getIdleCount(status));  
  25.         }  
  26.     }  
  27. }  

    UDP客户端:
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public class UdpClient {  
  2.     private static IoSession session = null;  
  3.     public static void main(String[] args) {  
  4.         NioDatagramConnector connect = new NioDatagramConnector();  
  5.         connect.setHandler(new UDPClientHandler());  
  6.         try{  
  7.             ConnectFuture future = connect.connect(new InetSocketAddress("127.0.0.1",9234));  
  8.             future.awaitUninterruptibly();  
  9.             session = future.getSession();  
  10.             //增加连接建立完成后的监听器。  
  11.             //若在建立完成后才添加监听器,监听器将马上执行  
  12.             future.addListener(new IoFutureListener<ConnectFuture>(){  
  13.                 public void operationComplete(ConnectFuture future) {  
  14.                     if( future.isConnected() ){  
  15.                         try {  
  16.                             sendData();  
  17.                         } catch (InterruptedException e) {  
  18.                             e.printStackTrace();  
  19.                         }  
  20.                     } else {  
  21.                         System.out.println(("Not connected...exiting"));  
  22.                     }  
  23.                 }  
  24.             });  
  25.         }catch(Exception e){  
  26.               
  27.         }finally{  
  28.             if(session!=null){  
  29.                 session.getCloseFuture().awaitUninterruptibly();  
  30.             }  
  31.         }  
  32.         connect.dispose();  
  33.     }  
  34.   
  35.     private static void sendData() throws InterruptedException {  
  36.         long free = Runtime.getRuntime().freeMemory();  
  37.         IoBuffer buffer = IoBuffer.allocate(8);  
  38.         buffer.putLong(free);  
  39.         buffer.flip();  
  40.         session.write(buffer);  
  41.         //因为是UDP,客户端需主动关闭连接  
  42.         session.close(false);  
  43.     }  
  44.     static class UDPClientHandler extends IoHandlerAdapter{}  
  45. }  

结语

    这一节介绍了mina的组件结构和框架体系,用几个案例简单介绍了下mina的使用方法。在日常的开发中,其实已经足够了。
0 0
原创粉丝点击