Apache Mina是一个能够帮助用户开发高性能和高伸缩性网络应用程序的框架。它通过Java nio技术基于TCP/IP和UDP/IP协议提供了抽象的、事件驱动的、异步的API。当前发行的 MINA 版本支持基于 Java NIO 技术的 TCP/UDP应用程序开发、串口通讯程序(只在最新的预览版中提供),MINA 所支持的功能也在进一步的扩展中。
API文档:
http://tool.oschina.net/apidocs/apidoc?api=mina
基础知识:
J2SE 基础知识
TCP协议:三次握手,四次挥手以及滑动窗口协议
UDP协议:封装报文
目标:通过Mina写一个简单的入门服务端程序
基本知识点: 1、Mina的概述
2、准备jar文件
3、初步理解编码器、解码器
4、实例练习
通过Mina创建一个服务端程序,用于监听客户端连接,并接受客户端发送过来的数据,当数据时exit时,那么服务端关闭。客户端通过telnet来模拟。
所需jar包
或者使用log4j2,部分pom如下
<!-- Mina核心 -->
<!-- https://mvnrepository.com/artifact/org.apache.mina/mina-core -->
<dependency>
<groupId>org.apache.mina</groupId>
<artifactId>mina-core</artifactId>
<version>2.0.19</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<!-- 日志处理 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j2.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j2.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>${log4j2.version}</version>
</dependency>
编码/解码
在应用程序中数据时Java对象或基本数据类型,而在网络传输中,为二进制传输,所以在传输前需要进行编码,传输后需要进行解码
服务端程序实例
创建一个非阻塞的server端的Socket
设置编码过滤器(使用Mina提供的文本换行符编解码器)
设置读取数据的缓冲区大小
设置读写通道无操作进入空闲状态的时间 10ms
绑定真正的逻辑处理
绑定端口
/*
测试Mina的简单例子
*/
public class MinaServer {
private final static Logger logger = LogManager.getLogger(MinaServer.class);
// 绑定的端口
private static final int MINA_PORT = 7080;
public static void main(String[] args) {
IoAcceptor acceptor;
try {
// 创建一个非阻塞的server端的Socket
acceptor = new NioSocketAcceptor();
// 设置编码过滤器(使用Mina提供的文本换行符编解码器)
acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(
new TextLineCodecFactory(
Charset.forName("UTF-8"),
LineDelimiter.WINDOWS.getValue(),
LineDelimiter.WINDOWS.getValue()
)
));
// 添加自定义的过滤器
acceptor.getFilterChain().addFirst("filter", new MyServerFilter());
// 设置读取数据的缓冲区大小
acceptor.getSessionConfig().setReadBufferSize(1024);
// 设置读写通道无操作进入空闲状态的时间 10ms
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
// 绑定真正的逻辑处理
acceptor.setHandler(new MyHandler());
// 绑定端口
acceptor.bind(new InetSocketAddress(MINA_PORT));
logger.info("Mina服务端启动成功,监听:" + MINA_PORT);
} catch (IOException e) {
e.printStackTrace();
logger.error("服务端启动出错-----" + e);
}
}
}
逻辑处理,继承IoHandlerAdapter:
public class MyHandler extends IoHandlerAdapter {
private static final Logger logger = LogManager.getLogger(MyHandler.class);
public MyHandler() {
super();
}
@Override
public void sessionCreated(IoSession session) throws Exception {
logger.info("服务端与客户端连接成功");
}
@Override
public void sessionOpened(IoSession session) throws Exception {
logger.info("服务端与客户端连接打开");
}
@Override
public void sessionClosed(IoSession session) throws Exception {
logger.info("服务端与客户端连接关闭");
}
@Override
public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
logger.info("服务端进入空闲状态");
}
@Override
public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
logger.error("服务端发生异常", cause);
}
@Override
public void messageReceived(IoSession session, Object message) throws Exception {
logger.info("服务端接受到消息:" + message);
// 如果接受到exit,则退出程序
if (message.equals("exit")) {
session.closeNow();
}
Date date = new Date();
session.write(date);
}
@Override
public void messageSent(IoSession session, Object message) throws Exception {
logger.info("服务端发送消息成功");
}
@Override
public void inputClosed(IoSession session) throws Exception {
logger.info("输入关闭");
}
}
启动后,使用cmd的telnet模拟客户端测试:
telnet 127.0.0.1 7080
测试界面打印出的消息:
客户端程序
创建一个非阻塞的客户端
设置超时时间
设置编码解码器
绑定逻辑处理类
创建连接
等待连接创建完成
获取连接session
发送数据
等待关闭连接
(与服务端代码相似,不同的是服务端创建的是NioSocketAcceptor,而客户端创建的是NioSocketConnector)
/*
Mina客户端
*/
public class MinaClient {
// 定义IP地址
private static final String MINA_HOST = "127.0.0.1";
// 定义端口
private static final int MINA_PORT = 7080;
public static void main(String[] args) {
IoSession ioSession;
// 创建一个非阻塞的客户端
IoConnector ioConnector = new NioSocketConnector();
// 设置超时时间
ioConnector.setConnectTimeoutMillis(30000);
// 设置编码解码器
ioConnector.getFilterChain().addLast("codec", new ProtocolCodecFilter(
new TextLineCodecFactory(
Charset.forName("UTF-8"),
LineDelimiter.WINDOWS.getValue(),
LineDelimiter.WINDOWS.getValue()
)
));
// 添加自定义过滤器
ioConnector.getFilterChain().addFirst("filter", new MyClientFilter());
// 绑定逻辑处理类
ioConnector.setHandler(new MyClientHandler());
// 创建连接
ConnectFuture future = ioConnector.connect(new InetSocketAddress(MINA_HOST, MINA_PORT));
// 等待连接创建完成
future.awaitUninterruptibly();
// 获取连接session
ioSession = future.getSession();
// 发送数据
ioSession.write("你好啊,Mina");
// 等待关闭连接
ioSession.getCloseFuture().awaitUninterruptibly();
ioConnector.dispose();
}
}
客户端逻辑处理,同样继承IoHandlerAdapter
public class MyClientHandler extends IoHandlerAdapter {
private static final Logger logger = LogManager.getLogger(MyClientHandler.class);
@Override
public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
logger.error("客户端发生异常",cause);
}
@Override
public void messageReceived(IoSession session, Object message) throws Exception {
logger.info("客户端接收到数据:" + message);
}
}
启动之前的服务端和当前的客户端,两者进行了通信:
Mina基础服务端、客户端搭建完毕 。