本文使用mina-2.0.16.jar
Apache Mina Server 是一个网络通信应用框架,也就是说,它主要是对基于TCP/IP、UDP/IP协议栈的通信框架(当然,也可以提供JAVA 对象的序列化服务、虚拟机管道通信服务等),Mina 可以帮助我们快速开发高性能、高扩展性的网络通信应用,Mina 提供了事件驱动、异步(Mina 的异步IO 默认使用的是JAVA NIO 作为底层支持)操作的编程模型。
Mina 同时提供了网络通信的Server 端、Client 端的封装,无论是哪端,Mina 在整个网通通信结构中都处于如下的位置:可见Mina 的API 将真正的网络通信与我们的应用程序隔离开来,你只需要关心你要发送、接收的数据以及你的业务逻辑即可。同样的,无论是哪端,Mina 的执行流程如下所示:
(1) IoService:这个接口在一个线程上负责套接字的建立,拥有自己的Selector,监听是否有连接被建立。
(2) IoProcessor:这个接口在另一个线程上,负责检查是否有数据在通道上读写,也就是说它也拥有自己的Selector,这是与我们使用Java NIO 编码时的一个不同之处,通常在JavaNIO 编码中,我们都是使用一个Selector,也就是不区分IoService与IoProcessor 两个功能接口。另外,IoProcessor 负责调用注册在IoService 上的过滤器,并在过滤器链之后调用IoHandler。
(3) IoFilter:这个接口定义一组拦截器,这些拦截器可以包括日志输出、黑名单过滤、数据的编码(write 方向)与解码(read 方向)等功能,其中数据的encode 与decode是最为重要的、也是你在使用Mina 时最主要关注的地方。
(4) IoHandler:这个接口负责编写业务逻辑,也就是接收、发送数据的地方。
- 服务器端
/**
* mina服务器端
* @author mazaiting
*/
public class MinaServer {
/**
* 监听的端口
*/
private static final int PORT = 9123;
public static void start() throws IOException{
// 1. 创建IoAcceptor
IoAcceptor acceptor = new NioSocketAcceptor();
// 2. 加入日志记录过滤器,用SL4J库记录信息
acceptor.getFilterChain().addLast("logger", new LoggingFilter());
// 3. 加入编码过滤器,用于解码所有收到的信息,使用 new TextLineCodecFactory() r
// 发送的信息进行编码,返回是MINA自带的,功能有限,只能处理文本戒者String类型。
acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(
new TextLineCodecFactory(Charset.forName("UTF-8"))));
// 4. 设置ServerHandler, 自定义的Handler,TimeServerHandler
acceptor.setHandler(new TimerServerHandler());
// 5. 设置Session的对应I/O processor读缓存区大小2048,通常这个参数不需要设置
acceptor.getSessionConfig().setReadBufferSize(2048);
// 6. 设置空闲时间, 这里的BOTH_IDLE指EADER_IDLE和WRITER_IDLE都为10秒
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
// 7. 绑定监听端口9123.
// acceptor.bind(new InetSocketAddress("localhost",PORT));
acceptor.bind(new InetSocketAddress(PORT));
}
public static void main(String[] args) throws IOException {
start();
}
/**
* 服务器端消息处理器
* @author mazaiting
*/
public static class TimerServerHandler extends IoHandlerAdapter{
@Override
public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
/**
* 自定义异常处理, 要不然异常会被“吃掉”;
*/
cause.printStackTrace();
}
@Override
public void messageReceived(IoSession session, Object message) throws Exception {
/**
* 对接收到的消息(已经解码)迕行下一步处理,这里对收到的字符串进行判断,
* 如果是”quit”则断开连接;否则输出当前时间的字符串格式;
*/
String str = message.toString();
if (str.trim().equalsIgnoreCase("quit")) {
session.closeNow();
return;
}
Date date = new Date();
session.write(date.toString());
System.out.println("Message written...");
}
@Override
public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
/**
* 当Session处于IDLE状态的时候,输出空闲状态次数;
*/
System.out.println("IDLE:" + session.getIdleCount(status));
}
}
}
运行代码,在cmd(命令提示符) 中输入"telnet 127.0.0.1 9123",连接成功后随意输入字符,并按下回车,即可看到当前时间。
- 客户端
/**
* mina客户端
* @author mazaiting
*/
public class MinaClient {
/**
* 监听的端口
*/
private static final int PORT = 9123;
public static void start() {
IoConnector connector = new NioSocketConnector();
connector.setConnectTimeoutMillis(30000);
connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(
new TextLineCodecFactory(Charset.forName("UTF-8"),
LineDelimiter.WINDOWS.getValue(),
LineDelimiter.WINDOWS.getValue())));
connector.setHandler(new ClientHandler("你好!\r\n 大家好!"));
connector.connect(new InetSocketAddress("localhost", 9123));
}
public static void main(String[] args) {
start();
}
private static class ClientHandler extends IoHandlerAdapter{
private String values;
public ClientHandler(String values) {
this.values = values;
}
@Override
public void sessionOpened(IoSession session) throws Exception {
session.write(values);
}
@Override
public void messageReceived(IoSession session, Object message) throws Exception {
System.out.println(message.toString());
}
}
}