mina
简介
mina是一个网络应用框架,能够使我们更容易开发出高性能高扩展的网络应用。基于java NIO,在TCP UDP之上提供了抽象的异步事件驱动API。
Quick Start Guide
时间服务器
1 import java.io.IOException; 2 import java.net.InetSocketAddress; 3 import java.nio.charset.Charset; 4 5 import org.apache.mina.core.service.IoAcceptor; 6 import org.apache.mina.core.session.IdleStatus; 7 import org.apache.mina.filter.codec.ProtocolCodecFilter; 8 import org.apache.mina.filter.codec.textline.TextLineCodecFactory; 9 import org.apache.mina.filter.logging.LoggingFilter; 10 import org.apache.mina.transport.socket.nio.NioSocketAcceptor; 11 12 public class MinaTimeServer { 13 private static final int PORT = 9123; 14 15 public static void main(String[] args) throws IOException { 16 17 IoAcceptor acceptor = new NioSocketAcceptor(); 18 acceptor.getFilterChain().addLast("logger", new LoggingFilter()); 19 acceptor.getFilterChain().addLast("codec", 20 new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8")))); 21 // 处理客户端请求 实现IoHandlerAdapter 22 acceptor.setHandler(new TimeServerHandler()); 23 // 设置缓冲区大小 24 acceptor.getSessionConfig().setReadBufferSize(2048); 25 // 当session空闲的时候检查的行为,每10秒前触发 26 acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10); 27 acceptor.bind(new InetSocketAddress(PORT)); 28 }
1 package com.mina; 2 3 import java.util.Date; 4 5 import org.apache.mina.core.service.IoHandlerAdapter; 6 import org.apache.mina.core.session.IdleStatus; 7 import org.apache.mina.core.session.IoSession; 8 9 public class TimeServerHandler extends IoHandlerAdapter { 10 @Override 11 public void exceptionCaught(IoSession session, Throwable cause) throws Exception { 12 cause.printStackTrace(); 13 } 14 15 @Override 16 public void messageReceived(IoSession session, Object message) throws Exception { // 获取客户端的message 17 String str = message.toString(); 18 if (str.trim().equalsIgnoreCase("quit")) { 19 session.close(); 20 return; 21 } 22 23 Date date = new Date(); 24 // 回写给client 25 session.write(date.toString() + "@@" + str); 26 System.out.println("Message written..."); 27 } 28 29 @Override // session保持空闲10秒以后触发执行,在acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 30 // 10)设置 31 public void sessionIdle(IoSession session, IdleStatus status) throws Exception { 32 33 System.out.println("IDLE " + session.getIdleCount(status)); 34 } 35 }
测试:
在dos中输入: telnet 127.0.0.1 9123
mina 架构
基于mina的应用分三层:
- I/O Service - 执行真实的I/O
- I/O Filter Chain - 转换字节到指定的数据结构
- I/O Handler - 处理业务逻辑
服务端架构:为每一个client创建一个session。 client架构:
日志过滤器
选择正确的jar
案例:
配置log4j.properties
1 # Set root logger level to DEBUG and its only appender to A1. 2 log4j.rootLogger=DEBUG, A1 3 4 # A1 is set to be a ConsoleAppender. 5 log4j.appender.A1=org.apache.log4j.ConsoleAppender 6 7 # A1 uses PatternLayout. 8 log4j.appender.A1.layout=org.apache.log4j.PatternLayout 9 log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c{1} %x - %m%n
acceptor.getFilterChain().addLast("logging", new LoggingFilter());
IoHandler Events
session
每一次client连接server,client和server都会创建一个新的session,用于存储持久化信息。
session状态: 检测session API:isActive() isClosing() isConnected()
打开session:
session = connector.connect(address).getSession();
设置自定义属性:
int counterValue = session.getAttribute( "counter" ); session.setAttribute( "counter", counterValue + 1 );
session返回应用数据:
session.write( <your message> );
session配置及统计,详见官网API。
过滤器
过滤器在IOService和IoHandler之间吹所有的I/O时间和请求。
mina提供的过滤器:
实现一个自定义过滤器:继承IoFilterAdapter
public class MyFilter extends IoFilterAdapter { @Override public void sessionOpened(NextFilter nextFilter, IoSession session) throws Exception { // Some logic here... nextFilter.sessionOpened(session); // Some other logic here... } }
传输协议
APR传输:
导入必要的jar:tomcat-apr-5.5.23.jar tomcat-native.jar
改变上面的时间服务器,change the NioSocketAcceptor to AprSocketAcceptor.
serial传输:详见http://mina.apache.org/mina-project/userguide/ch6-transports/serial-transport.html
Handler处理器
- sessionCreated
- sessionOpened
- sessionClosed
- sessionIdle
- exceptionCaught
- messageReceived
- messageSent
I0Buffer
作为ByteBuffer的替代,不使用NIO缓冲区的理由有下面2个:
1)没有提供有用的getters和putters;
2)由于capacity是固定的,很难实现写入可变长度数据;
实现自动伸缩和扩展:
exp1 IoBuffer buffer = IoBuffer.allocate(8); buffer.setAutoExpand(true); //自动扩展 buffer.putString("12345678", encoder); // Add more to this buffer buffer.put((byte)10); exp2 IoBuffer buffer = IoBuffer.allocate(16); buffer.setAutoShrink(true); //自动伸缩 buffer.put((byte)1); System.out.println("Initial Buffer capacity = "+buffer.capacity()); buffer.shrink(); System.out.println("Initial Buffer capacity after shrink = "+buffer.capacity()); buffer.capacity(32); System.out.println("Buffer capacity after incrementing capacity to 32 = "+buffer.capacity()); buffer.shrink(); System.out.println("Buffer capacity after shrink= "+buffer.capacity());