MINA 快速入门

简介:

Apache MINA 是一个网络应用的框架,可以帮助用户开发的高性能、高扩展性的网络应用程序。它通过 Java NIO 提供了一个抽象的事件驱动的异步 API 用在不同传输协议上,比如 TCP/IP 和 UDP/IP 等。

本教程介绍了如何构建基于 MINA 的应用的过程。这个教程介绍的是构建一个 Time Server(时间服务器)。

本教程需要以下先决条件:

  • MINA 2.0 +
  • 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

例如,slf4j-log4j12.jar 和 log4j-1.3.x.jar 一起使用的话,将会发生故障

环境

本示例开发环境为:

  • Maven 3.2.x
  • Eclipse 4.x

你可以选用你喜欢的任意 IDE。

编写 MINA 时间服务器

我们以创建一个叫做 MinaTimeServer.java 的文件开始。初始化代码如下:

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

这段程序对所有人来说都很简单明了。我们简单定义了一个用于启动程序的 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 类就绪了,我们继续定义处理类并绑定 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) ); 的调用。这个方法定义了这一服务器要监听到的主机和端口。最后一个方法是 IoAcceptor.bind() 调用。这个方法将会绑定到指定端口并开始处理远程客户端请求。

接下来我们在配置中添加一个过滤器。这个过滤器将会日志记录所有信息,比如 session 的新建、接收到的消息、发送的消息、session 的关闭。接下来的过滤器是一个 ProtocolCodecFilter。这个过滤器将会把二进制或者协议特定的数据翻译为消息对象,反之亦然。我们使用一个现有的 TextLine 工厂因为它将为你处理基于文本的消息 (你无须去编写 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) );
 }
}

接下来,我们将定义用于服务客户端连接和当前时间的请求的处理器。处理器类是一个必须实现 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 进行 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 设置了输入缓冲区大小以及 idle 属性。指定缓冲区大小以通知底层操作系统为传入的数据分配多少空间。第二行指定了什么时候检查空闲 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。exceptionCaught 应该总是在处理器中进行定义,以处理正常的远程连接过程时抛出的异常。如果这一方法没有定义,可能无法正常报告异常。

exceptionCaught 方法将会对错误和 session 关闭进行简单 stack trace 打印。对于更多的程序,这将是常规,除非处理器能够从异常情况下进行恢复。

messageReceived 方法会从客户端接收数据并将当前时间回写给客户端。如果接收自客户端的消息是单词 "quit",那么当前 session 将被关闭。这一方法也会向客户端打印输出当前时间。取决于你所使用的协议编解码器,传递到这一方法的对象 (第二个参数) 会有所不同,就和你传给 session.write(Object) 方法的对象一样。如果你不定义一个协议编码器,你很可能会接收到一个 IoBuffer 对象,而且被要求写出一个 IoBuffer 对象。

一旦 session 保持空闲状态到达 acceptor.getSessionConfig().setIdleTime( IdleStatus.BOTH_IDLE, 10 ); 所定义的时间长度,sessionIdle 方法会被调用。

剩下的工作就是定义服务器端将要监听的 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:

客户端输出 服务端输出
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...

源码

译者注:翻译版本的项目源码见 https://github.com/waylau/apache-mina-2-user-guide-demos 中的com.waylau.mina.demo.time包下

接下来是什么?

通过上面例子演示,你可以基于 MINA 很简单的就写出了一个 NIO 服务器。如果你已经对 MINA 产生了兴趣,可以继续去阅读其他教程,比如 《Apache MINA 2 用户指南》。在 JAVA 世界里,类似的 NIO 框架还有 Netty,可参考《Netty 4.x 用户指南》。有意思的是,这两个框架是同个作者。

目录
相关文章
|
10月前
|
编解码 前端开发 搜索推荐
如何建立自己的体育直播平台-源码搭建全流程
随着在线观看体育赛事用户的爆发式增长,搭建专业体育直播应用成为趋势。利用如熊猫比分的全链路解决方案,创业者可快速启动平台。主要步骤包括前期技术准备(赛事API接口、服务器配置、域名选择、短信服务、云直播服务)、定制化(LOGO标识、功能测试与优化)及正式上线与运营(推广、持续更新、主播入驻)。此方案使创业者能高效进入体育市场,抓住机遇。
|
8月前
|
物联网 程序员 芯片
你知道Hi3861芯片吗,支持OpenHarmony系统
本文介绍华为Hi3861芯片,该芯片集成了WiFi和蓝牙功能,具备低功耗、高集成度、强大通信能力和丰富接口资源,广泛应用于智能家居、智能穿戴、工业物联网和智慧城市等领域,助力开发者实现高效物联网解决方案。
345 0
你知道Hi3861芯片吗,支持OpenHarmony系统
|
11月前
|
存储 人工智能 监控
分享5款让办公学习井井有条的小工具
本文介绍了五款实用的Win10小工具:Folder Painter用于文件夹图标自定义;CustomizerGod实现系统界面个性化;3171.CN提供多种在线工具;XMeters监控系统资源;QuickCut管理快捷方式,帮助提升办公学习效率。
283 1
|
11月前
|
边缘计算 分布式计算 资源调度
云计算与边缘计算的融合趋势与挑战
云计算与边缘计算的融合趋势与挑战
300 3
|
开发工具 git Windows
IDEA如何对比不同分支某个文件的差异
【9月更文挑战第28天】该指南介绍了在IDEA中使用Git工具窗口进行分支对比的方法。首先,通过底部工具栏或菜单打开Git窗口;接着,在“Branches”选项卡中查看所有分支;然后选择要对比的分支和文件,并通过右键菜单启动对比;最后,在“Diff”视图中查看详细差异,包括新增和删除内容的颜色标记。此外,还提供了使用内置终端执行`git diff`命令进行对比的可选方法。
2232 4
|
供应链 监控 安全
云 HIS 系统的药品库存管理功能的特性
云HIS系统在药品库存管理方面引入了实时监控、智能预警、高效采购、精确追溯等多项新特性,提升了管理效率和准确性。系统支持多终端访问,实现自动化流程,并确保合规性和数据安全,同时还可与供应链集成,优化库存结构,提供全方位的药品管理解决方案。
373 4
云 HIS 系统的药品库存管理功能的特性
WK
|
12月前
|
测试技术 开发者 Python
python模块化设计
Python的模块化设计支持开发者将代码拆分成独立模块,提升代码的可读性、可维护性和复用性。通过`.py`文件定义模块,并利用`import`语句导入所需功能,同时可通过包含`__init__.py`的目录创建包以组织多个模块。Python按特定顺序搜索模块,支持修改`sys.path`添加自定义路径。此外,支持相对与绝对导入方式,便于灵活使用模块资源。遵循良好的编程习惯有助于开发高质量的可复用模块,而虚拟环境与依赖管理工具则确保项目间的依赖隔离,进一步增强项目的稳定性和可扩展性。
WK
212 2
|
12月前
|
Linux
linux开机挂载镜像
【10月更文挑战第1天】在 Linux 系统中,开机挂载镜像通常涉及几个关键步骤,包括创建挂载点、编辑配置文件以及重新加载配置
467 0
|
前端开发 BI
前端基础(十)_标签分类(行级标签、块级标签、行块标签)
本文阐述了HTML标签的分类,包括行级标签、块级标签和行块标签,并展示了如何使用CSS的display属性实现标签类型之间的转换。
435 3
|
关系型数据库 MySQL 数据库
Mysql—8.0.21下载安装配置教程
该教程介绍了MySQL的下载与安装步骤。建议从官网下载MySQL 8.0及以上版本,也可通过提供的百度网盘链接获取。解压后,在指定目录创建my.ini配置文件,并替换basedir和datadir为自己实际的安装路径。接着,将MySQL安装目录的bin文件夹添加到系统环境变量Path中。以管理员模式运行CMD,进入bin目录,使用`mysqld --initialize --console`初始化数据库,记下生成的临时密码。最后,用`net start mysql`启动服务,`mysql -u root -p`登录并使用ALTER指令修改初始密码。
1004 1