设为首页 收藏本站
查看: 1337|回复: 0

[经验分享] Apache Mina(一)

[复制链接]

尚未签到

发表于 2015-7-30 15:51:26 | 显示全部楼层 |阅读模式
  Apache Mina是一个能够帮助用户开发高性能和高伸缩性网络应用程序的框架。它通过Java nio技术基于TCP/IP和UDP/IP协议提供了抽象的、事件驱动的、异步的API。
  Mina包的简介:

org.apache.mina.core.buffer用于缓冲区的IoBuffer
org.apache.mina.core.service
org.apache.mina.transport.*
用于提供连接的service
org.apache.mina.core.session用于提供两端状态的session
org.apache.mina.core.filterchain
org.apache.mina.filter.*
用于拦截所有IO事件和请求的filter chain和各类拦截器(在IoService和IoHandler之间)
org.apache.mina.handler.*用于处理IO事件的handler
org.apache.mina.core.future用于实现异步IO操作的 future
org.apache.mina.core.polling用于实现IO轮询的的polling
org.apache.mina.proxy.*用于实现代理的proxy
  先介绍Mina几个重要接口:


  • IoServiece :这个接口在一个线程上负责套接字的建立,拥有自己的 Selector,监听是否有连接被建立。
  • IoProcessor :这个接口在另一个线程上负责检查是否有数据在通道上读写,也就是说它也拥有自己的 Selector,这是与我们使用 JAVA NIO 编码时的一个不同之处,通常在 JAVA NIO 编码中,我们都是使用一个 Selector,也就是不区分 IoService与 IoProcessor 两个功能接口。另外,IoProcessor 负责调用注册在 IoService 上的过滤器,并在过滤器链之后调用 IoHandler。
  • IoAccepter :相当于网络应用程序中的服务器端
  • IoConnector :相当于客户端
  • IoSession :当前客户端到服务器端的一个连接实例
  • IoHandler :这个接口负责编写业务逻辑,也就是接收、发送数据的地方。这也是实际开发过程中需要用户自己编写的部分代码。
  • IoFilter :过滤器用于悬接通讯层接口与业务层接口,这个接口定义一组拦截器,这些拦截器可以包括日志输出、黑名单过滤、数据的编码(write 方向)与解码(read 方向)等功能,其中数据的 encode与 decode是最为重要的、也是你在使用 Mina时最主要关注的地方。
DSC0000.jpg MIINA架构图
  在图中的模块链中,IoService 便是应用程序的入口,相当于我们前面代码中的 IoAccepter,IoAccepter 便是 IoService 的一个扩展接口。IoService 接口可以用来添加多个 IoFilter,这些 IoFilter 符合责任链模式并由 IoProcessor 线程负责调用。而 IoAccepter 在 ioService 接口的基础上还提供绑定某个通讯端口以及取消绑定的接口。



IoAcceptor acceptor = new SocketAcceptor();
  上面代码中,相当于我们使用了 Socket 通讯方式作为服务的接入,当前版本的 MINA 还提供了除 SocketAccepter 外的基于数据报文通讯的 DatagramAccepter 以及基于管道通讯的 VmPipeAccepter。另外还包括串口通讯接入方式,目前基于串口通讯的接入方式已经在最新测试版的 MINA 中提供。你也可以自行实现 IoService 接口来使用自己的通讯方式。
  而在上图中最右端也就是 IoHandler,这便是业务处理模块。在业务处理类中不需要去关心实际的通讯细节,只管处理客户端传输过来的信息即可。编写 Handler 类就是使用 MINA 开发网络应用程序的重心所在,相当于 MINA 已经帮你处理了所有的通讯方面的细节问题。为了简化 Handler 类,MINA 提供了 IoHandlerAdapter 类,此类仅仅是实现了 IoHandler 接口,但并不做任何处理。
  一个 IoHandler 接口中具有如下一些方法(摘自 MINA 的 API 文档):


  • void exceptionCaught(IoSession session, Throwable cause)
                        当接口中其他方法抛出异常未被捕获时触发此方法
  • void messageReceived(IoSession session, Object message)
    当接收到客户端的请求信息后触发此方法
  • void messageSent(IoSession session, Object message)
    当信息已经传送给客户端后触发此方法
  • void sessionClosed(IoSession session)
    当连接被关闭时触发,例如客户端程序意外退出等等
  • void sessionCreated(IoSession session)
    当一个新客户端连接后触发此方法
  • void sessionIdle(IoSession session, IdleStatus status)
                        当连接空闲时触发此方法
  • void sessionOpened(IoSession session)
                        当连接后打开时触发此方法,一般此方法与 sessionCreated 会被同时触发
  前面我们提到 IoService 是负责底层通讯接入,而 IoHandler 是负责业务处理的。那么 MINA 架构图中的 IoFilter 作何用途呢?答案是你想作何用途都可以。但是有一个用途却是必须的,那就是作为 IoService 和 IoHandler 之间的桥梁。IoHandler 接口中最重要的一个方法是 messageReceived,这个方法的第二个参数是一个 Object 型的消息,总所周知,Object 是所有 Java 对象的基础,那到底谁来决定这个消息到底是什么类型呢?答案也就在这个 IoFilter 中。在前面使用的例子中,我们添加了一个 IoFilter 是 new ProtocolCodecFilter(new TextLineCodecFactory()),这个过滤器的作用是将来自客户端输入的信息转换成一行行的文本后传递给 IoHandler,因此我们可以在 messageReceived 中直接将 msg 对象强制转换成 String 对象。
  而如果我们不提供任何过滤器的话,那么在 messageReceived 方法中的第二个参数类型就是一个 byte 的缓冲区,对应的类是 org.apache.mina.core.buffer.IoBuffer。虽然你也可以将解析客户端信息放在 IoHandler 中来做,但这并不是推荐的做法,使原来清晰的模型又模糊起来,变得 IoHandler 不只是业务处理,还得充当协议解析的任务。
  MINA自身带有一些常用的过滤器,例如LoggingFilter(日志记录)、BlackListFilter(黑名单过滤)、CompressionFilter(压缩)、SSLFilter(SSL加密)等。
  
  简单地来讲,就分为三层:


  • I/O Service :负责处理I/O。
  • I/O Filter Chain :负责编码处理,字节到数据结构或数据结构到字节的转换等,即非业务逻辑的操作。
  • I/O Handle :负责处理业务逻辑。
  客户端的通信过程:


  • 通过SocketConnector同服务器端建立连接。
  • 链接建立之后I/O的读写交给了I/O Processor线程,I/O Processor是多线程的。
  • 通过I/O Processor读取的数据经过IoFilterChain里所有配置的IoFilter,IoFilter进行消息的过滤,格式的转换,在这个层面可以制定一些自定义的协议。
  • 最后IoFilter将数据交给Handler进行业务处理,完成了整个读取的过程。
  • 写入过程也是类似,只是刚好倒过来,通过IoSession.write写出数据,然后Handler进行写入的业务处理,处理完成后交给IoFilterChain,进行消息过滤和协议的转换,最后通过I/O Processor将数据写出到socket通道。
  IoFilterChain作为消息过滤链


  • 读取的时候是从低级协议到高级协议的过程,一般来说从byte字节逐渐转换成业务对象的过程。
  • 写入的时候一般是从业务对象到字节byte的过程。
DSC0001.png 客户端通信过程   IoSession贯穿整个通信过程的始终
  创建服务器



import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
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.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
public class MinaTimeServer {
// 定义监听端口
private static final int PORT = 6488;
public static void main(String[] args) throws IOException {
// 创建服务端监控线程
IoAcceptor acceptor = new NioSocketAcceptor();
acceptor.getSessionConfig().setReadBufferSize(2048);
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
// 设置日志记录器
acceptor.getFilterChain().addLast("logger", new LoggingFilter());
// 设置编码过滤器
        acceptor.getFilterChain().addLast(
"codec",
new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));
// 指定业务逻辑处理器
acceptor.setHandler(new TimeServerHandler());
// 设置端口号
acceptor.bind(new InetSocketAddress(PORT));
// 启动监听线程
        acceptor.bind();
}
}


import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
/**
* 服务器端业务逻辑
*/
public class TimeServerHandler extends IoHandlerAdapter {
/**
* 连接创建事件
*/
@Override
public void sessionCreated(IoSession session){
// 显示客户端的ip和端口
        System.out.println(session.getRemoteAddress().toString());
}
@Override
public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
cause.printStackTrace();
}
/**
* 消息接收事件
*/
@Override
public void messageReceived(IoSession session, Object message) throws Exception {
String strMsg = message.toString();
if (strMsg.trim().equalsIgnoreCase("quit")) {
session.close(true);
return;
}
// 返回消息字符串
session.write("Hi Client!");
// 打印客户端传来的消息内容
System.out.println("Message written : " + strMsg);
}
@Override
public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
System.out.println("IDLE" + session.getIdleCount(status));
}
}
  客户端



import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
public class MinaTimeClient {
public static void main(String[] args){
// 创建客户端连接器.
NioSocketConnector connector = new NioSocketConnector();
connector.getFilterChain().addLast("logger", new LoggingFilter());
connector.getFilterChain().addLast("codec",
new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));
// 设置连接超时检查时间
connector.setConnectTimeoutCheckInterval(30);
connector.setHandler(new TimeClientHandler());
// 建立连接
ConnectFuture cf = connector.connect(new InetSocketAddress("192.168.2.109", 6488));
// 等待连接创建完成
        cf.awaitUninterruptibly();
cf.getSession().write("Hi Server!");
cf.getSession().write("quit");
// 等待连接断开
        cf.getSession().getCloseFuture().awaitUninterruptibly();
// 释放连接
        connector.dispose();
}
}


import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
public class TimeClientHandler extends IoHandlerAdapter {
public void messageReceived(IoSession session, Object message) throws Exception {
String content = message.toString();
System.out.println("client receive a message is : " + content);
}
public void messageSent(IoSession session, Object message) throws Exception {
System.out.println("messageSent -> :" + message);
}
}
  
  
  
  http://my.oschina.net/ielts0909/blog?catalog=253154
  http://www.blogjava.net/mikechen/archive/2012/03/15/371938.html
  http://dxf1122.blog.163.com/blog/static/54041004200931371414356/
  http://blog.sina.com.cn/s/blog_7abc61de0100sdoi.html
  http://mina.apache.org/mina-project/documentation.html
  http://wenku.baidu.com/view/b9af67c34028915f804dc292.html
  http://wenku.baidu.com/view/46800bce0508763231121232.html
  http://wenku.baidu.com/view/5ccc7935b90d6c85ec3ac6e7.html
  
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-92375-1-1.html 上篇帖子: Win下Eclipse提交hadoop程序出错:org.apache.hadoop.security.AccessControlException: Permi 下篇帖子: 全部用startssl生成的证书,配置Apache使其支持SSL
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表