在这篇文章中主要讲解如下内容:
1.mina 简介
1.1 mina 分布图
1.2 mina 组件图
2.例子
2.1 服户端实现
2.2 客户端实现
2.3 日志配置
3.运行结果
1.简介
由于最近项目要用OBD定位车载终端,让其中的数据经过系统分析更人性化的发送到客户的手机、网站中。所以就想到了mina这个东西,通过它来实现现有需求。
mina是个什么东西了?简单介绍下:
Apache的MINA是一个网络应用框架,它可以帮助用户轻松地开发高性能和高可扩展性的网络应用。它提供了一个抽象的事件驱动和通过Java NIO实现的各种传输协议异步API,如TCP / IP和UDP/ IP。
对于mina可以直接到apache官网:http://mina.apache.org/downloads-mina.html 下载
1.1分布图
下面看看mina的分布层图:

通过上图,我们可以看到MINA是界于:你的应用程序(客户端或服务器)和底层的网络层之间。这个网络层它可以基于TCP,UDP或者和一个虚拟机交互。
在开发中,你不用考虑复杂的network层,你只要基于的mina架构上开发你的应用程序就可以了。
1.2 组件图
下面我们们通过mina的内部来更深入的了解细节,可以参看下面的mina架构的组件图:

从广义上讲,基于MINA的应用程序分为3层
I/O服务 - 执行实际I/O
I/O过滤器链 - 过滤器,将字节转换成所需的数据结构或者将数据结构转换成字节
I/O处理器 - 在这里驻留实际的业务逻辑
因此,为了创建一个基于MINA的应用,你必须:
创建I/O服务已经提供的服务(*接受器) - 选择已有的或创建自己的
创建一个过滤器链 - 从已经存在的过滤器中选择或创建自定义过滤器转化的请求/响应
创建一个I/O处理器 - 写业务逻辑,处理不同的消息
下面我们就通过mina的这个原理,来实现一个tcp/ip的服务
2.例子
这个例子需要的基本的jar包有MINA 2.x Core、JDK 1.5 or greater、SLF4J 1.3.0 or greater,如果项目是用maven构建的,引入的包如下所示:
<dependency>
<groupId>org.apache.mina</groupId>
<artifactId>mina-core</artifactId>
<version>2.0.7</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.6</version>
</dependency>
2.1服务端
首先写一个mina 服务端MinaTcpServer.java
import java.io.IOException;
import java.net.InetSocketAddress;
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.serialization.ObjectSerializationCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
public class MinaTcpServer {
private static final int PORT = 9999;
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
/**
* 首先,我们需要一个侦听传入连接的对象。由于本程序是基于TCP/IP,所以我们添加一个ScoketAcceptor
*/
IoAcceptor acceptor = new NioSocketAcceptor();
/**
* 添加一个过虑器,用于记录一些信息,例如session的创建、消息接收、消息发送、session关闭
*/
acceptor.getFilterChain().addLast("logger", new LoggingFilter());
/**
* 再添加一个过滤器,用于将一些二进制信息或者指定的协议数据转换成消息对象,或者将一些发送的消息转换成二进制信息或者指定的协议数据
*/
acceptor.getFilterChain().addLast( "codec", new ProtocolCodecFilter(new ObjectSerializationCodecFactory()));
/**
* 我们需要定义一个事件处理器,主要是用于处理服务端接收客户端的连接和一些实时的请求。
* 这个事件处理器必须要继承IoHandler接口
*/
acceptor.setHandler(new MessageServerHandler());
/**
* 下面是配置一些信息,来指定于客户端连接的一些信息设定
*/
acceptor.getSessionConfig().setReadBufferSize(2048);
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
/**
* 下面是启动服务,并指定TCP/IP服务监听的端口
*/
acceptor.bind(new InetSocketAddress(PORT));
}
}
从上面代码中可以看出,服务端需要一个处理事件的类,而这个类需要实现IoHandler接口.在mina的核心包中有个IoHandlerAdapter类,这个类实现了IoHandler接口,但是所有的方法都未进行实际的业务处理。一般在开发中都是基于这个类来实现的.
下面是MessageServerHandler.java的代码:
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MessageServerHandler extends IoHandlerAdapter {
private final static Logger LOGGER = LoggerFactory
.getLogger(MessageServerHandler.class);
@Override
public void messageReceived( IoSession session, Object message ) throws Exception
{
LOGGER.info("服务端接收消息");
AddMessage message2 = (AddMessage) message;
ResultMessage resultMessage = new ResultMessage();
if(message2.getSequence() % 2 == 0){
resultMessage.setOk(true);
}else {
resultMessage.setOk(false);
}
resultMessage.setSequence(message2.getSequence());
resultMessage.setValue(message2.getValue());
session.write(resultMessage);
LOGGER.info("服务端发送消息");
}
}
这个类我主要是重写了消息接收这个方法。对于来处客户端的消息,我将其转换成一个对象AddMessage,然后将这个对象进行处理后转换成ResultMessage对象。最后将转换后的对象通过session.write()方法返回到客户端。
MessageServerHandler.java这个类中用到的两个类,就是两个基本的java bean,因为这两个类需要进行TCP传输,而且在MinaTcpServer.java类中我们添加的数据转换设置是ObjectSerializationCodecFactory这个类,也就是对客户端传来的对象进行序列化。所以,我们需要在创建AddMessage和ResultMessage这两个类时要实现Serializable接口。
为了方便,我先定义一个抽象类来作处理:AbstractMessage.java
import java.io.Serializable;
public class AbstractMessage implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private int sequence;
public int getSequence() {
return sequence;
}
public void setSequence(int sequence) {
this.sequence = sequence;
}
}
然后看看AddMessage.java代码:
public class AddMessage extends AbstractMessage {
/**
*
*/
private static final long serialVersionUID = 1L;
private int value;
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
@Override
public String toString(){
return getSequence() + ":ADD(" + value + ")";
}
}
ResultMessage.java代码如下所示:
public class ResultMessage extends AbstractMessage {
/**
*
*/
private static final long serialVersionUID = 1L;
private boolean ok;
private int value;
public boolean isOk() {
return ok;
}
public void setOk(boolean ok) {
this.ok = ok;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
@Override
public String toString(){
if(ok){
return getSequence() + ":RESULT(" + value + ")";
}else {
return getSequence() + ":RESULT(ERROR)";
}
}
}
以上就是服务端的代码以及一些po对象,下面来看看客户端的实现
2.2客户端
首先客户端需要定义一个客户端连接的服务SimpleTcpClient.java
import java.net.InetSocketAddress;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.serialization.ObjectSerializationCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
public class SampleTcpClient {
private static final long CONNECT_TIMEOUT = 25000;
private static final String HOSTNAME = "127.0.0.1";
private static final int PORT = 9999;
private static int[] values = { 1, 2, 3 };
/**
* @param args
*/
public static void main(String[] args) {
//客户端建立连接通道
NioSocketConnector connector = new NioSocketConnector();
//设置超时时间
connector.setConnectTimeoutMillis(CONNECT_TIMEOUT);
//设置连接时传输数据时的数据转换方式
connector.getFilterChain().addLast(
"codec",
new ProtocolCodecFilter(new ObjectSerializationCodecFactory()));
//记录一些session状态的信息
connector.getFilterChain().addLast("logger", new LoggingFilter());
//设置客户端的处理事件
connector.setHandler(new ClientSessionHandler(values));
IoSession session = null;
//绑定到服务中
ConnectFuture future = connector.connect(new InetSocketAddress(
HOSTNAME, PORT));
//等待连接服务
future.awaitUninterruptibly();
//获取连接时的session对象
session = future.getSession();
//等待session的关闭
session.getCloseFuture().awaitUninterruptibly();
//关闭session连接
connector.dispose();
}
}
对于客户端连接的服务也需要一个客户端的整件处理,它的功能与服务端的事件处理功能是一致的。下面来看看实现的代码.
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.wy.mina.message.AddMessage;
import com.wy.mina.message.ResultMessage;
public class ClientSessionHandler extends IoHandlerAdapter {
private final static Logger LOGGER = LoggerFactory
.getLogger(ClientSessionHandler.class);
private final int[] values;
private boolean finished;
public ClientSessionHandler(int[] values) {
this.values = values;
}
public boolean isFinished() {
return finished;
}
@Override
public void sessionOpened(IoSession session) {
// 客户端发送消息
for (int i = 0; i < values.length; i++) {
AddMessage m = new AddMessage();
m.setSequence(i);
m.setValue(values[i]);
session.write(m);
}
}
@Override
public void messageReceived(IoSession session, Object message) {
//接收服务端返回的信息
ResultMessage rm = (ResultMessage) message;
if (rm.isOk()) {
if (rm.getSequence() == values.length - 1) {
// print the sum and disconnect.
LOGGER.info("The sum: " + rm.getValue());
session.close(true);
finished = true;
}
} else {
LOGGER.warn("Server error, disconnecting...");
session.close(true);
finished = true;
}
}
@Override
public void exceptionCaught(IoSession session, Throwable cause) {
LOGGER.info("client session close.....");
session.close(true);
}
}
通过上面看出,客户端的事件处理,主要是在session打开时,发送信息到服务端,和在服务端返回数据时,以返回的数据进行的处理。
2.3 日志配置
因为在些例子中,我用到了slf4j,所以为了让例子顺利的执行,内存中不能存在任何错误,否则,这个例子将运行不成功(客户端和服务端交互不成功).日志的配置很简单,我们就简单的添加一个日志配置。在maven构建的项目src/main/resources根目录下添加一个log4j.properties,里面的具体内容如下所示:
# Set root logger level to DEBUG and its only appender to A1.
log4j.rootLogger=DEBUG, A1
# A1 is set to be a ConsoleAppender.
log4j.appender.A1=org.apache.log4j.ConsoleAppender
# A1 uses PatternLayout.
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c{1} %x - %m%n
3.运行
上面就完成了一个TCP/IP的小例子,下面我们就可以运行了.首先运行服务端MinaTimeServer.java类,然后再运行客户端SimpleTcpClient.java类。运行客户端后运行的结果如下所示:
客户端运行结果:
0 [NioProcessor-2] INFO LoggingFilter - CREATED
0 [NioProcessor-2] INFO LoggingFilter - OPENED
11 [NioProcessor-2] INFO LoggingFilter - SENT: 0:ADD(1)
11 [NioProcessor-2] INFO LoggingFilter - SENT: 1:ADD(2)
11 [NioProcessor-2] INFO LoggingFilter - SENT: 2:ADD(3)
21 [NioProcessor-2] DEBUG ProtocolCodecFilter - Processing a MESSAGE_RECEIVED for session 1
31 [NioProcessor-2] INFO LoggingFilter - RECEIVED: 0:RESULT(1)
31 [NioProcessor-2] DEBUG ProtocolCodecFilter - Processing a MESSAGE_RECEIVED for session 1
31 [NioProcessor-2] INFO LoggingFilter - RECEIVED: 1:RESULT(ERROR)
31 [NioProcessor-2] WARN ClientSessionHandler - Server error, disconnecting...
31 [NioProcessor-2] INFO LoggingFilter - RECEIVED: 2:RESULT(3)
31 [NioProcessor-2] INFO ClientSessionHandler - The sum: 3
31 [NioProcessor-2] INFO LoggingFilter - CLOSED
服务端运行结果:
0 [NioProcessor-2] INFO LoggingFilter - CREATED
0 [NioProcessor-2] INFO LoggingFilter - OPENED
21 [NioProcessor-2] INFO LoggingFilter - RECEIVED: HeapBuffer[pos=0 lim=93 cap=2048: 00 00 00 59 AC ED 00 05 73 72 01 00 1E 63 6F 6D...]
21 [NioProcessor-2] DEBUG ProtocolCodecFilter - Processing a MESSAGE_RECEIVED for session 1
31 [NioProcessor-2] INFO MessageServerHandler - 服务端接收消息
31 [NioProcessor-2] INFO MessageServerHandler - 服务端发送消息
31 [NioProcessor-2] INFO LoggingFilter - SENT: HeapBuffer[pos=0 lim=0 cap=0: empty]
31 [NioProcessor-2] INFO LoggingFilter - RECEIVED: HeapBuffer[pos=0 lim=186 cap=2048: 00 00 00 59 AC ED 00 05 73 72 01 00 1E 63 6F 6D...]
31 [NioProcessor-2] DEBUG ProtocolCodecFilter - Processing a MESSAGE_RECEIVED for session 1
31 [NioProcessor-2] INFO MessageServerHandler - 服务端接收消息
31 [NioProcessor-2] INFO MessageServerHandler - 服务端发送消息
31 [NioProcessor-2] INFO MessageServerHandler - 服务端接收消息
31 [NioProcessor-2] INFO MessageServerHandler - 服务端发送消息
31 [NioProcessor-2] INFO LoggingFilter - SENT: HeapBuffer[pos=0 lim=0 cap=0: empty]
31 [NioProcessor-2] INFO LoggingFilter - SENT: HeapBuffer[pos=0 lim=0 cap=0: empty]
41 [NioProcessor-2] INFO LoggingFilter - CLOSED
对于源码,因为项目中还有其它的例子,在这里就不上传了,博客中都将所有的代码粘贴出来了,只要读者一个个拷就可以顺利运行。
本文介绍Apache MINA框架及其在网络应用开发中的使用,包括MINA的架构原理、核心组件及如何构建TCP/IP服务端与客户端。通过具体代码示例展示了MINA在Java NIO基础上实现异步事件驱动的网络通信。
894

被折叠的 条评论
为什么被折叠?



