MINA快速入门指南


概述

本教程将带你参观基于MINA的程序构建过程。本教程将构建一个time server。本教程要求的先决条件如下:

  • MINA2.x Core
  • JDK1.5或更高
  • SLF4J1.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
    • java.util.logging用户:slf4j-api.jar和slf4j-jdk14.jar
    • 重要的是:请确保你正在使用正确匹配你日志框架的slf4j-*.jar。

例如,slf4j-log4j12.jar和log4j-1.3.x.jar不能一起使用,会引起故障。

我们在Windows2000专业版和linux上测试了本程序。如果看到这个程序有任何问题,请不要犹豫,立即联系我们以便于告知MINA开发者。另外,本教程试图保持独立的开发环境(IDE,编辑器,等等)。本教程将使用任何你决定舒服的环境。为了简洁,编辑命令和步骤直行程许已经移除。如果你需要帮助学习怎么编译和执行java程序,请查阅Java教程。

编写Mina time服务

我们开始先创建一个MinaTimeServer.java文件,初始代码如下:

public class MinaTimeServer {
   public static void main(String[] args) {
       // code will go here next
   }
}

这个代码应该很简单。我们简单的定义一个main方法,这个main方法将用于开启程序。这个时候,我们开始添加代码构建我们的服务。首先,我们需要一个对象,用于监听进来的连接。因为这个程序基于TCP/IP,我们添加一个SocketAcceptor到我们程序里。

import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
public class MinaTimeServer
{
   public static void main( String[] args )
   {
       IoAcceptor acceptor = new NioSocketAcceptor();
   }
}

随着NioSocketAcceptor类就位,我们可以继续定义handler类并绑定NioSocketAcceptor到一个端口:

import java.net.InetSocketAddress;
import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
public class MinaTimeServer
{
   private static final int PORT = 9123;
   public static void main( String[] args ) throws IOException
   {
       IoAcceptor acceptor = new NioSocketAcceptor();
       acceptor.bind( new InetSocketAddress(PORT) );
   }
}

就像你看到的一样,有一个调用acceptor.setLocalAddress(new InetSocketAddress(Port);这个方法定义这个服务监听什么host和port。最后的方法是调用IoAcceptor.bind()。这个方法会绑定制定的端口并开始处理远程客户端。

下一步我们在配置里添加一个过滤器。这个过滤器将记录所有信息,如新创建的session、messages received、message sent、session closed。下一个过滤器是ProtocalCodecFilter。这个过滤器将转化二进制或协议特定的数据到消息对象。我们使用存在的TextLine factory,因为他将为你处理文本消息(你没必要编写codec部分)。

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
public class MinaTimeServer
{
   public static void main( String[] args )
   {
       IoAcceptor acceptor = new NioSocketAcceptor();
       acceptor.getFilterChain().addLast( "logger", new LoggingFilter() );
       acceptor.getFilterChain().addLast( "codec", new ProtocolCodecFilter( new TextLineCodecFactory( Charset.forName( "UTF-8" ))));
       acceptor.bind( new InetSocketAddress(PORT) );
   }
}

这个时候,我们将定义handler用于服务客户端连接和当前时间的请求。handler类必须要实现接口IoHandler。几乎所有使用MINA的项目,这个是程序的主力,因为他服务于所有来自客户端的请求。对于本教程,我们将扩展IoHandlerAdapter。这个是适配器设计模式,它简化了实现IoHandler接口需要重新的代码数量。

import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
public class MinaTimeServer
{
   public static void main( String[] args ) throws IOException
   {
       IoAcceptor acceptor = new NioSocketAcceptor();
       acceptor.getFilterChain().addLast( "logger", new LoggingFilter() );
       acceptor.getFilterChain().addLast( "codec", new ProtocolCodecFilter( new TextLineCodecFactory( Charset.forName( "UTF-8" ))));
       acceptor.setHandler(  new TimeServerHandler() );
       acceptor.bind( new InetSocketAddress(PORT) );
   }
}

现在我们添加NioSocketAcceptor配置。这将可让我们进行对用于从客户端接收连接的socket细节设置。

import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
public class MinaTimeServer
{
   public static void main( String[] args ) throws IOException
   {
       IoAcceptor acceptor = new NioSocketAcceptor();
       acceptor.getFilterChain().addLast( "logger", new LoggingFilter() );
       acceptor.getFilterChain().addLast( "codec", new ProtocolCodecFilter( new TextLineCodecFactory( Charset.forName( "UTF-8" ))));
       acceptor.setHandler(  new TimeServerHandler() );
       acceptor.getSessionConfig().setReadBufferSize( 2048 );
       acceptor.getSessionConfig().setIdleTime( IdleStatus.BOTH_IDLE, 10 );
       acceptor.bind( new InetSocketAddress(PORT) );
   }
}

MinaTimeServer类里新加了两行。这些方法设置Iohandler,session的输入缓冲区大小和空闲属性。缓冲区大小的指定用于告诉底层操作系统给进来的数据分配多少空间。第二行将指定什么时候检测空闲session。调用setIdleTime里,第一个参数定义决定session是否空闲时,什么动作检测,第二个参数定义时间长度,必须在session认为空闲之前发生。

处理器代码如下所示:

import java.util.Date;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
public class TimeServerHandler extends IoHandlerAdapter
{
   @Override
   public void exceptionCaught( IoSession session, Throwable cause ) throws Exception
   {
       cause.printStackTrace();
   }
   @Override
   public void messageReceived( IoSession session, Object message ) throws Exception
   {
       String str = message.toString();
       if( str.trim().equalsIgnoreCase("quit") ) {
           session.close();
           return;
       }
       Date date = new Date();
       session.write( date.toString() );
       System.out.println("Message written...");
   }
   @Override
   public void sessionIdle( IoSession session, IdleStatus status ) throws Exception
   {
       System.out.println( "IDLE " + session.getIdleCount( status ));
   }
}

这个案例中用到的方法是exceptionCaught,messageReceived和sessionidle。定义在处理器的exception应该处理远程连接到异常。如果没有定义这个方法,异常可能不会得到正确的报告。

exceptionCaught方法简单的错误打印堆栈信息并关闭session。对于绝大多数程序,这是标准的做法,除非处理器可以从异常条件中恢复。

messageReceived方法将从客户端接收数据并将当前时间写会到客户端。如果从客户端接收的消息是单词"quit",就会关闭session。这个方法还将答应当前时间到客户端。根据你看到的协议编解码器,进到这个方法里的对象是不同的,和传到session.write(Object)方法里的对象一样。如果你没指定协议编解码器,你会接收一个IoBuffer对象,并且要写出一个IoBuffer对象。

一旦session保持acceptor.getSessionConfig.setIdleTime(IdleStatus.BOTH_IDLE,10)里的时间空闲,就会调用sessionIdle方法。

剩下的就是定义服务监听的套接字地址,以及真实的启动服务。代码如下:

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
public class MinaTimeServer
{
   private static final int PORT = 9123;
   public static void main( String[] args ) throws IOException
   {
       IoAcceptor acceptor = new NioSocketAcceptor();
       acceptor.getFilterChain().addLast( "logger", new LoggingFilter() );
       acceptor.getFilterChain().addLast( "codec", new ProtocolCodecFilter( new TextLineCodecFactory( Charset.forName( "UTF-8" ))));
       acceptor.setHandler( new TimeServerHandler() );
       acceptor.getSessionConfig().setReadBufferSize( 2048 );
       acceptor.getSessionConfig().setIdleTime( IdleStatus.BOTH_IDLE, 10 );
       acceptor.bind( new InetSocketAddress(PORT) );
   }
}

试用Time server

这个时候,我们可以继续并编译程序。一旦你编译了程序,你就可以运行程序以便于测试会发生什么。测试程序的最简单方式是启动程序,然后telnet进这个程序:

客户端输出

user@myhost:~> telnet 127.0.0.1 9123

Trying 127.0.0.1...

Connected to 127.0.0.1.

Escape character is '^]'.

hello

Wed Oct 17 23:23:36 EDT 2007

quit

Connection closed by foreign host.

user@myhost:~>

服务端输出

MINA Time server started.

Message written...

接下来是什么?

请访问我们的文档页面,找出更多资源。你还可以继续阅读其他教程。

 

原创文章,转载请注明出处:转载自小马过河 - MINA快速入门指南


Jbone

Spring Cloud实战项目jbone正在开发中, jbone功能包括服务管理、单点登录、系统管理平台、内容管理平台、电商平台、支付平台、工作流平台等子系统。欢迎关注!

我要关注
马军伟
关于作者 马军伟
写的不错,支持一下

先给自己定个小目标,日更一新。