您的位置:首页 > 理论基础 > 计算机网络

MINA2.0用户手册中文版--第二章 第二节 TCP服务端实例

2013-09-11 11:00 375 查看
本教程将引导创建一个基于MINA的程序实例,例子是一个时间服务器,需要以下先决条件:

MINA 2.x Core
JDK 1.5 或 更高版本
SLF4J 1.3.0 或 更高版本

Log4J 1.2用户: slf4j-api.jar, slf4j-log4j12.jar, and Log4J 1.2.x
Log4J 1.3用户 : slf4j-api.jar, slf4j-log4j13.jar, and Log4J 1.3.x
java.util.logging用户 : slf4j-api.jar and slf4j-jdk14.jar
提醒:请核实你使用了正确的slf4j-*.jar来匹配你所选择的日志框架

例如,slf4j-log4j12.jar和log4j-1.3.x.jar不能够搭配使用工作,会使日志模块不起作用。

该程序在Windows© 2000专业版和Linux上都可通过测试;如果你使用该程序的过程中有任何问题,请毫不迟疑的通知我们以便提醒MINA的开发者;另外,该教程的程序不需要依赖任何特殊的开发环境(如平台或编辑器等),它可以在任何你习惯的环境下运行。为了教程的简洁,编译和执行改程序的步骤就省略掉了,如果你需要学习怎样编译或执行Java程序,你可以参考“Java教程”。

编写MINA时间服务器

以创建一个名为MinaTimeServer.java的源文件开始,初始代码如下:

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


这段代码对于所有人来说应该都是很明了的了,我们简单的定义了一个main方法用来启动这个程序,这时,我们就开始添加代码来构造我们的服务器。第一步,我们需要创建一个对象用来监听所有接入的连接。因为这个程序是基于TCP/UDP的,我们将添加一个SocketAcceptor在我们的程序中。

import org.apache.mina.transport.socket.nio.NioSocketAcceptor;

public class MinaTimeServer
{
public static void main( String[] args )
{
IoAcceptor acceptor = new NioSocketAcceptor();
}
}


在类NioSocketAcceptor被创建之后,我们就可以继续定义一个处理程序类,并将这个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.bind( new InetSocketAddress(PORT) ),这个方法定义了这个服务将要监听的主机和端口,并开始接收传入的连接。

接下来,我们添加一个过滤器的配置,这个过滤器将记录所有的日志信息,如新创建了会话,接收消息,发送消息和会话关闭等。下一个过滤器是协议编解码过滤器ProtocolCodecFilter,这个过滤器可以将二进制文件或协议特定数据转换为消息对象,或进行反向转换。这里,我们使用了一个已存在的文本行转换工厂,它可以替你处理基于文本的消息转换(你不需要自己实现这个):

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) );
}
}


接下来,我们将定义可同时为来自不同客户端的请求进行服务的处理程序,处理程序类必须实现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,其中,第一个参数定义了用什么策略来检查一个会话是否空闲,第二个参数定义了一个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。

在一个处理程序中,exceptionCaught应该总是被定义为捕捉在正常处理远程连接时候抛出的异常,如果不定义这个方法,异常发生时可能不会正确的被通知。

本例中的exceptionCaught方法只是简单的打印出堆栈跟踪的错误信息并将该session关闭,多数情况下,这是个标准的做法,除非处理程序可以做到从异常中恢复。

例子中的messageReceived方法将接收客户端数据进行处理并立刻返回给客户端数据。如果从客户端接收到单词“quit”,则会关闭该session,该方法依然会在客户端打印出系统当前时间。借助于所使用的协议编码解码器,该方法传递的对象(方法中的第二个参数Object message)和原来的相比会有所变化,同样,使用session.write(Object)方法进行传递的对象也会是不同的。如果不指定一个协议编解码器,你接收到的将很有可能是一个IoBuffer对象,同时,你也必须返回一个IoBuffer对象。

sessionIdle方法会在一个session闲置了acceptor.getSessionConfig().setIdleTime( IdleStatus.BOTH_IDLE, 10 )中定义的时间后被调用。

最后要做的是定义服务器要监听的socket地址,并通过调用主方法启动服务器,该代码如下所示:

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) );
}
}



试用该时间服务器:

这时,我们就可以继续进行编译操作,一旦编译过该程序,就可以执行改程序并测试会发生什么。最简单的测试该服务器的方法是启动该程序,并通过telnet测试改程序:
Client OutputServer Output
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...



下一步是什么呢?

请访问文档页以了解更多资源,你也可以继续阅读其他教程。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: