《mina中文开发手册资料》由会员分享,可在线阅读,更多相关《mina中文开发手册资料(47页珍藏版)》请在金锄头文库上搜索。
1、 Apache Mina Server 2.0 中文参考手册中文参考手册中文参考手册中文参考手册 李海峰李海峰李海峰李海峰(QQ:61673110)-Andrew830314 Apache Mina Server 是一个网络通信应用框架,也就是说,它主要是对基于 TCP/IP、UDP/IP 协议栈的通信框架(当然,也可以提供 JAVA 对象的序列化服务、虚拟机管道通信服务等) , Mina 可以帮助我们快速开发高性能、高扩展性的网络通信应用,Mina 提供了事件驱动、异 步(Mina 的异步 IO 默认使用的是 JAVA NIO 作为底层支持)操作的编程模型。 Mina 主要有 1.x 和 2
2、.x 两个分支,这里我们讲解最新版本 2.0,如果你使用的是 Mina 1.x, 那么可能会有一些功能并不适用。学习本文档,需要你已掌握 JAVA IOJAVA IOJAVA IOJAVA IO、JAVA NIOJAVA NIOJAVA NIOJAVA NIO、JAVA JAVA JAVA JAVA SocketSocketSocketSocket、JAVA JAVA JAVA JAVA 线程及并发库线程及并发库线程及并发库线程及并发库(java.util.concurrent(java.util.concurrent(java.util.concurrent(java.util.concur
3、rent.*.*.*.*) ) ) )的知识。 Mina 同时提供了网络通信的 Server 端、Client 端的封装,无论是哪端,Mina 在整个网通 通信结构中都处于如下的位置: 可见 Mina 的 API 将真正的网络通信与我们的应用程序隔离开来,你只需要关心你要发送、 接收的数据以及你的业务逻辑即可。 同样的,无论是哪端,Mina 的执行流程如下所示: (1.) IoService:这个接口在一个线程上负责套接字的建立,拥有自己的 Selector,监 听是否有连接被建立。 (2.) IoProcessor:这个接口在另一个线程上负责检查是否有数据在通道上读写,也就是 说它也拥有自己
4、的 Selector,这是与我们使用 JAVA NIO 编码时的一个不同之处, 通常在 JAVA NIO 编码中,我们都是使用一个 Selector,也就是不区分 IoService 与 IoProcessor 两个功能接口。另外,IoProcessor 负责调用注册在 IoService 上 的过滤器,并在过滤器链之后调用 IoHandler。 (3.) IoFilter:这个接口定义一组拦截器,这些拦截器可以包括日志输出、黑名单过滤、 数据的编码 (write 方向) 与解码 (read 方向) 等功能, 其中数据的 encode 与 decode 是最为重要的、也是你在使用 Mina 时
5、最主要关注的地方。 (4.) IoHandler:这个接口负责编写业务逻辑,也就是接收、发送数据的地方。 _ 1.1.1.1. 简单的简单的简单的简单的 TCPServerTCPServerTCPServerTCPServer: (1.)(1.)(1.)(1.) 第一步第一步第一步第一步:编写编写编写编写 IoServiceIoServiceIoServiceIoService 按照上面的执行流程,我们首先需要编写 IoService,IoService 本身既是服务端,又是客 户端, 我们这里编写服务端, 所以使用 IoAcceptor 实现, 由于 IoAcceptor 是与协议无关的,
6、因为我们要编写 TCPServer, 所以我们使用 IoAcceptor 的实现 NioSocketAcceptor, 实际上 底层就是调用java.nio.channels.ServerSocketChannel类。 当然, 如果你使用了Apache 的 APR 库, 那么你可以选择使用 AprSocketAcceptor 作为 TCPServer 的实现, 据传说 Apache APR 库的性能比 JVM 自带的本地库高出很多。 那么 IoProcessor 是由指定的 IoService 内部创建并调用的,我们并不需要关心。 public class MyServer mainmainm
7、ainmain 方法方法方法方法: IoAcceptor acceptor=new NioSocketAcceptor(); acceptor.getSessionConfig().setReadBufferSize(2048); acceptor.getSessionConfig.setIdleTime(IdleStatus.BOTH_IDLE,10); acceptor.bind(new InetSocketAddress(9123); 这段代码我们初始化了服务端的 TCP/IP 的基于 NIO 的套接字,然后调用 IoSessionConfig 设置读取数据的缓冲区大小、读写通道均在 1
8、0 秒内无任何操作就进入空闲状态。 (2.)(2.)(2.)(2.) 第二步第二步第二步第二步:编写过滤器编写过滤器编写过滤器编写过滤器 这里我们处理最简单的字符串传输,Mina 已经为我们提供了 TextLineCodecFactory 编解码 器工厂来对字符串进行编解码处理。 acceptor.getFilterChain().addLast(“codec“, new ProtocolCodecFilter( new TextLineCodecFactory( Charset.forName(“UTF-8“), LineDelimeter. WINDOWS.getValue(), Line
9、Delimiter. WINDOWS.getValue() ) ) ); 这段代码要在 acceptor.bind()方法之前执行, 因为绑定套接字之后就不能再做这些准备工 作了。 这里先不用清楚编解码器是如何工作的,这个是后面重点说明的内容,这里你只需要清楚, 我们传输的以换行符为标识的数据,所以使用了 Mina 自带的换行符编解码器工厂。 (3.)(3.)(3.)(3.) 第三步第三步第三步第三步:编写编写编写编写 IoHandlerIoHandlerIoHandlerIoHandler 这里我们只是简单的打印 Client 传说过来的数据。 public class MyIoHandle
10、r extends IoHandlerAdapter / 这里我们使用的SLF4J作为日志门面,至于为什么在后面说明。 private final static Logger log = LoggerFactory .getLogger(MyIoHandler.class); Override public void messageReceived(IoSession session, Object message) throws Exception String str = message.toString(); log.info(“The message received is “ + s
11、tr + “); if (str.endsWith(“quit“) session.close(true); return; 然后我们把这个 IoHandler 注册到 IoService: acceptor.setHandler(new MyIoHandler(); 当然这段代码也要在 acceptor.bind()方法之前执行。 然后我们运行 MyServer 中的 main 方法,你可以看到控制台一直处于阻塞状态,此时,我们 用 telnet 127.0.0.1 9123 访问,然后输入一些内容,当按下回车键,你会发现数据在 Server 端被输出,但要注意不要输入中文,因为 Windo
12、ws 的命令行窗口不会对传输的数据 进行 UTF-8 编码。当输入 quit 结尾的字符串时,连接被断开。 这里注意你如果使用的操作系统,或者使用的 Telnet 软件的换行符是什么,如果不清楚, 可以删掉第二步中的两个红色的参数,使用 TextLineCodec 内部的自动识别机制。 _ 2.2.2.2. 简单的简单的简单的简单的 TCPTCPTCPTCPClientClientClientClient: 这里我们实现 Mina 中的 TCPClient, 因为前面说过无论是 Server 端还是 Client 端, 在 Mina 中的执行流程都是一样的。唯一不同的就是 IoService
13、的 Client 端实现是 IoConnector。 (1.)(1.)(1.)(1.) 第一步第一步第一步第一步:编写编写编写编写 IoServiceIoServiceIoServiceIoService 并注册过滤器并注册过滤器并注册过滤器并注册过滤器 public class MyClient mainmainmainmain 方法方法方法方法: IoConnector connector=new NioSocketConnector(); connector.setConnectTimeoutMillis(30000); connector.getFilterChain().addLas
14、t(“codec“, new ProtocolCodecFilter( new TextLineCodecFactory( Charset.forName(“UTF-8“), LineDelimiter.WINDOWS.getValue(), LineDelimiter.WINDOWS.getValue() ) ) ); connector.connect(new InetSocketAddress(“localhost“, 9123); (2.)(2.)(2.)(2.) 第三步第三步第三步第三步:编写编写编写编写 IoHandlerIoHandlerIoHandlerIoHandler pu
15、blic class ClientHandler extends IoHandlerAdapter private final static Logger LOGGER = LoggerFactory .getLogger(ClientHandler.class); private final String values; public ClientHandler(String values) this.values = values; Override public void sessionOpened(IoSession session) session.write(values); 注册 IoHandler: connector.setHandler(new ClientHandler(“你好!rn 大家好!“); 然后我们运行 MyClient,你会发现 MyServer 输出如下语句: The message received is 你好! The message received is 大家好! 我们看到服务端是按照收到两条消息输出的, 因为我们用的编解码器是以换行符判断数据是 否读取完毕的。 _