标签:
英文:
This tutorial will walk you through the process of building a MINA based program. This tutorial will walk through building a time server. The following prerequisites are required for this tutorial:
MINA 2.0.7 Core
JDK 1.5 or greater
[SLF4J|http://www.slf4j.org/] 1.3.0 or greater
Log4J 1.2 users: slf4j-api.jar, slf4j-log4j12.jar, and Log4J 1.2.x
Log4J 1.3 users: slf4j-api.jar, slf4j-log4j13.jar, and Log4J 1.3.x
java.util.logging users: slf4j-api.jar and slf4j-jdk14.jar
IMPORTANT : Please make sure you are using the right slf4j-*.jar that matches to your logging framework. For instance, slf4j-log4j12.jar and log4j-1.3.x.jar can not be used together, and will malfunction.
I have tested this program on both Windows漏 2000 professional and linux. If you have any problems getting this program to work, please do not hesitate to [contact us|Contact] in order to talk to the MINA developers. Also, this tutorial has tried to remain independent of development environments (IDE, editors..etc). This tutorial will work with any environment that you are comfortable with. Compilation commands and steps to execute the program have been removed for brevity. If you need help learning how to either compile of execute java programs, please consult the Java tutorial.
We will begin by creating a file called MinaTimeServer.java. The initial code can be found below: :::Java public class MinaTimeServer {
public static void main(String[] args) { // code will go here next }}
This code should be straightforward to all. We are simply defining a main method that will be used to kick off the program. At this point, we will begin to add the code that will make up our server. First off, we need an object that will be used to listen for incoming connections. Since this program will be TCP/IP based, we will add a SocketAcceptor to our program.
import org.apache.mina.core.service.IoAcceptor;import org.apache.mina.transport.socket.nio.NioSocketAcceptor;public class MinaTimeServer{ public static void main( String[] args ) { IoAcceptor acceptor = new NioSocketAcceptor(); }}
With the NioSocketAcceptor class in place, we can go ahead and define the handler class and bind the NioSocketAcceptor to a port.
Next we add a filter to the configuration. This filter will log all information such as newly created sessions, messages received, messages sent, session closed. The next filter is a ProtocolCodecFilter. This filter will translate binary or protocol specific data into message object and vice versa. We use an existing TextLine factory because it will handle text base message for you (you don‘t have to write the codec part)
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" )))); }}
At this point, we will define the handler that will be used to service client connections and the requests for the current time. The handler class is a class that must implement the interface IoHandler. For almost all programs that use MINA, this becomes the workhorse of the program, as it services all incoming requests from the clients. For this tutorial, we will extend the class IoHandlerAdapter. This is a class that follows the adapter design pattern which simplifies the amount of code that needs to be written in order to satisfy the requirement of passing in a class that implements the IoHandler interface.
import java.io.IOException;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() ); }}
We will now add in the NioSocketAcceptor configuration. This will allow us to make socket-specific settings for the socket that will be used to accept connections from clients.
import java.io.IOException;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 ); }}
There are 2 new lines in the MinaTimeServer class. These methods set the set the IoHandler, input buffer size and the idle property for the sessions. The buffer size will be specified in order to tell the underlying operating system how much room to allocate for incoming data. The second line will specify when to check for idle sessions. In the call to setIdleTime, the first parameter defines what actions to check for when determining if a session is idle, the second parameter defines the length of time in seconds that must occur before a session is deemed to be idle.
The code for the handler is shown below:
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 )); }}
The methods used in this class are exceptionCaught, messageReceived and sessionIdle. exceptionCaught should always be defined in a handler to process and exceptions that are raised in the normal course of handling remote connections. If this method is not defined, exceptions may not get properly reported.
The exceptionCaught method will simply print the stack trace of the error and close the session. For most programs, this will be standard practice unless the handler can recover from the exception condition.
The messageReceived method will receive the data from the client and write back to the client the current time. If the message received from the client is the word "quit", then the session will be closed. This method will also print out the current time to the client. Depending on the protocol codec that you use, the object (second parameter) that gets passed in to this method will be different, as well as the object that you pass in to the session.write(Object) method. If you do not specify a protocol codec, you will most likely receive a IoBuffer object, and be required to write out a IoBuffer object.
The sessionIdle method will be called once a session has remained idle for the amount of time specified in the callacceptor.getSessionConfig().setIdleTime( IdleStatus.BOTH_IDLE, 10 );.
All that is left to do is define the socket address that the server will listen on, and actually make the call that will start the server. That code is shown below:
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) ); }}
中文:
MINA 2.0.7 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
java.util.logging 用户: slf4j-api.jar 和slf4j-jdk14.jar
重要提醒:请确认你使用的slf4j-*.jar
和你的logging框架匹配。举个板栗,slf4j-log4j12.jar 和 log4j-1.3.x.jar 是不能混在一起用的,否则会出问题。
We will begin by creating a file called MinaTimeServer.java
我们创建一个文件名为 MinaTimeServer.java
,文件内容如下:
public class MinaTimeServer{ public static void main( String[] args ) { //还没有东西呢 }}
上面的代码应该不用解释了吧,为了创建我们的服务,我们需要一个监听传入连接的对象,由于我们的项目是基于TCP/IP,所以需要一个SocketAcceptor
对象来帮我们处理。
import org.apache.mina.core.service.IoAcceptor;import org.apache.mina.transport.socket.nio.NioSocketAcceptor;public class MinaTimeServer{ public static void main( String[] args ) { IoAcceptor acceptor = new NioSocketAcceptor(); }}
创建好后,我们可以定义处理请求的类,和指定监听的端口等。
接下来,我们需要在配置里添加几个过滤器。第一个是logger
,这个过滤器用来记录所有的信息,比如创建session(会话),接收消息,发送消息,关闭会话等。第二个是ProtocolCodecFilter
(协议编解码过滤器).这个过滤器用来转换二进制或协议的专用数据到消息对象中, 反之亦然。我们这里使用一个已经存在的TextLine
工厂,因为我们这里只处理一些文字消息(你不需要再去写编解码部分)。
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" )))); }}
For this tutorial, we will extend the class IoHandlerAdapter. This is a class that follows the adapter design pattern which simplifies the amount of code that needs to be written in order to satisfy the requirement of passing in a class that implements the IoHandler interface.
接下来我们需要创建一个handler
来实时处理客户端的连接和请求,这个handler
类必须实现 IoHandler
这个接口。对于所有使用MINA的程序来说,主要的负荷都在这个文件,它为所有客户端请求提供服务。在这个例子中,我们将扩展IoHandlerAdapter
类。这是一个遵从适配器模式的类,帮我们简化了很多为了去实现IoHandler
接口的代码。
import java.io.IOException;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() ); }}
现在我们要添加一些NioSocketAcceptor
配置,这将允许我们设置特殊的socket设置来接收客户端的连接。
import java.io.IOException;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 ); }}
这有两行新代码,这些方法是用来为会话设置IoHandler
,输入缓冲区的大小和空闲等待时间。
需要指定缓冲区大小来告诉底层操作系统为传入的数据分配多少的空间。第二行指定多少时间没有读写操作就进入空闲状态。
handler
的代码如下:
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
这几个方法。exceptionCaught
应该总是在handler
中定义,来处理一些异常情况,否则异常信息将无法捕捉。
exceptionCaught
方法简单地打印了错误的堆栈跟踪和关闭会话。对于大多数程序,这将是标准的做法,除非处理程序可以从异常状态中恢复。
messageReceived 方法来处理从客户端接收到的数据,这里是将当前时间返回给客户端,当收到quit
时,会话将被关闭,也会返回一个当前时间给客户端。根据所使用的协议编解码器,object
这个参数传递的类型有所不同,以及返回的数据时的session.write(Object)
也不同。如果不指定协议的编解码器,你将收到一个类型为IoBuffer
的对象,返回的数据也要求是IoBuffer
。
The sessionIdle method will be called once a session has remained idle for the amount of time specified in the call acceptor.getSessionConfig().setIdleTime( IdleStatus.BOTH_IDLE, 10 );.sessionIdle
方法将定时调用一次会话,保持空闲状态。通过调用acceptor.getSessionConfig().setIdleTime( IdleStatus.BOTH_IDLE, 10 );
来设定时间间隔。
所有剩下要做的就是定义套接字地址,该服务器将侦听,实际接入时才会启动服务。
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) ); }}
到了这里后,服务端的操作就已经完成了,客户端可参考附件中代码,里面包含了完整的实例,来源自http://blog.csdn.net/hujunil/article/details/9923381。
代码结构
效果
客户端
服务端
源码下载:http://oss.loftor.com/usr/uploads/2014/08/3841585032.rar
标签:
原文地址:http://my.oschina.net/anna153/blog/371746