Mina 通信入门(二)-快速入门示例
Mina 通信入门(二)-快速入门示例
这一章节将通过一个简单的 Mina 的快速入门示例程序,让你快速了解 Mina 的基本用法。程序的逻辑很简单,就是服务器接收客户端发送的消息,并将其原样返回给客户端。客户端发送消息给服务器, 然后打印服务器返回的消息。
1. Mina 工作流程概述
在写 HelloWorld 之前,我们先看下面这张图 Mina 官网文档中一张工作流程图:
从图里可以看出,一个 Mina 应用会分为三个层次:
- IO Service: 执行具体的 I/O操作,这里是对 Java NIO 的封装。
- IO Filter Chain: 执行过滤、转换消息结构、打印日志等。 换句话来说就是还没有到具体的业务逻辑处理之前的一些处理链。
- IO Handler: 执行业务逻辑处理,比如收到数据存数据库、给客户端应答报文等。
这三个层次分别代表着三个 Java 接口:
- IoService
- IoFilter
- IoHandler
这三个接口基本就覆盖了整个 Mina 的使用,理解这三个接口是开发 Mina 应用很重要的一个环节。 在后面几张我们将逐步讲解这三个接口,这里是为了写 HelloWorld 之前先了解下需要用到 Mina 的哪些组件。
2. 编写服务端代码
服务端的大概逻辑如下:
实例化一个 NioSocketAcceptor 来处理客户端连接的接入,使用的是 NIO 模式。
实例化一个自定义的 ServerHandler 用来处理数据相关的业务逻辑。主要是实现
messageReceived
这个方法,用于处理收到数据时的操作。设置一个处理文本行的编码器和解码器,这样才可以将收到的字节流转换回原来的字符串形式,同时也可以将字符型转换成网络发送的字节流。
设置连接配置,如缓冲区大小、空闲超时时间等。
调用
bind
方法绑定服务器端口 8080 , 然后启动服务。
package com.suny.mina;
import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import java.io.IOException;
import java.net.InetSocketAddress;
public class MinaServer {
// 设置服务端固定暴露的端口号
private static final int PORT = 8080;
public static void main(String[] args) throws IOException {
// 创建 IoAcceptor 来处理连接的接入
IoAcceptor acceptor = new NioSocketAcceptor();
// 设置 IoHandler 来处理数据读取、数据写入等等业务逻辑
acceptor.setHandler(new ServerHandler());
// 添加一个处理文本行的编码器和解码器,这个很重要,没有将会报错
acceptor.getFilterChain().addLast("codec",
new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));
// 设置连接配置,这里暂时不要去纠结
acceptor.getSessionConfig().setReadBufferSize(2048);
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
// 绑定端口并启动服务器
acceptor.bind(new InetSocketAddress(PORT));
System.out.println("Mina服务暴露在端口 " + PORT);
}
private static class ServerHandler extends IoHandlerAdapter {
@Override
public void messageReceived(IoSession session, Object message) throws Exception {
String str = message.toString();
System.out.println("服务端收到客户端的消息: " + str);
// 将收到的消息原样发送回客户端
session.write(str);
}
@Override
public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
cause.printStackTrace();
}
}
}
3. 编写客户端代码
客户端的大概逻辑如下:
- 创建一个 NioSocketConnector 用于连接服务端,使用的是 NIO 模式。
- 创建 ClientHandler , 用于处理连接的I/O事件。主要的逻辑是重写了
messageReceived
方法,用于处理收到数据时的操作。 - 设置一个处理文本行的编码器和解码器,这样才可以将收到的字节流转换回原来的字符串形式,同时也可以将字符型转换成网络发送的字节流。
- 设置连接配置, 如缓冲区大小、空闲超时时间等。
- 调用
connect
方法连接服务端地址 localhost:8080 ,并等待连接成功。 - 调用
write
方法发送 HelloWorld, Mina! 到服务端。 - 等待接收服务器返回的消息。
- 关闭连接。
package com.suny.mina;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.service.IoConnector;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
import java.io.IOException;
import java.net.InetSocketAddress;
public class MinaClient {
private static final String HOST = "localhost";
private static final int PORT = 8080;
public static void main(String[] args) throws IOException {
// 创建IoConnector
IoConnector connector = new NioSocketConnector();
// 设置 IoHandler 来处理相关业务
connector.setHandler(new ClientHandler());
// 添加一个处理文本行的编码器和解码器,这个很重要,没有将会报错
connector.getFilterChain().addLast("codec",
new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));
// 设置连接配置,这里先不要纠结这几个参数
connector.getSessionConfig().setReadBufferSize(2048);
connector.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
// 连接到服务端 localhost:8080
ConnectFuture future = connector.connect(new InetSocketAddress(HOST, PORT));
future.awaitUninterruptibly();
// 获取IoSession
IoSession session = future.getSession();
// 发送消息给服务器
session.write("HelloWorld, Mina!");
// 等待接收服务器返回的消息
future.awaitUninterruptibly();
// 关闭连接
session.closeNow();
System.out.println("Mina 客户端声明周期结束.");
}
// 创建一个自定义的业务处理器
private static class ClientHandler extends IoHandlerAdapter {
@Override
public void messageReceived(IoSession session, Object message) throws Exception {
String str = message.toString();
System.out.println("客户端收到服务端的消息: " + str);
}
@Override
public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
cause.printStackTrace();
}
}
}
4. 运行示例程序
先启动服务器端的程序 , 再启动客户端的程序,这样才能看到下面的效果。
- 运行服务器端的
MinaServer
类,控制台输出:
Mina服务暴露在端口 8080
- 运行客户端的
MinaClient
类,控制台输出:
客户端收到服务端的消息: HelloWorld, Mina!
Mina 客户端声明周期结束.
同时,服务器端的控制台输出:
服务端收到客户端的消息: HelloWorld, Mina!
可以看到 , 客户端发送的消息 “HelloWorld, Mina!” 被服务器接收并原样返回, 客户端接收到服务器返回的消息后打印到控制台,然后关闭连接。
5. 小结
虽然这只是一个 Hello World 级别的程序,但是实际上生产的通信程序基本套路跟它是差不多的,只是在基础上增加了一些业务处理,同时各方面处理的更加完善。下一章节将开始介绍一下几个重要的组件 IoService、IoFilter、IoHandler 等。