Apache mina学习

来源:互联网 发布:网络歌手柔情的原名 编辑:程序博客网 时间:2024/04/28 01:31

Apache mina 学习


前言

最近研究RPC的异步机制是在Capnproto这个项目开始,大致看了一下说明和examples中的调用方式,采用了一种回调的方式,即调用发送后,会立即返回一个promise对象,然后Promise.then(){}这样可以去注册then中的回调函数。异步的RPC能够很好的提高系统的并发性能。由于C++实在比较长一段时间没有经常写了,然后一些新特性也不是很清楚,于是查了些资料,发现mina这个已经很早就出现的java版的网络应用框架里面也有一种future机制,实现异步通信和回调。因此想仔细看看。这篇就不描述代码分析了,主要讲下怎么使用和大概的结构。

mina介绍

Apache mina是apache出的一款以高性能为目标的异步非阻塞的网络应用程序框架。它让使用者很容易的建立起一个高性能的server而不必理会底层的协议例如是使用了UDP/TCP/Serial,并且还提供了In-VM Communication的方式,In-VM Communication还没时间去看,先不去管它,我们主要理解基于UDP/TCP的通信Server或者Client,Mina让这些变得很容易。并且实现了高性能(基于非阻塞和异步IO),同时mina提供了一系列的IoFilter可以自行设置,在接受和发送的过程中会调用,这写Filter可以用来实现logger,编码解码,黑名单等等。

mina的处理流程


上图中的上方是client,下方是server,最直接和用户接触的就是IoService,它会接受请求,在处理过程中在某些状态IoService也会调用IoFilterChain的firexxx函数来依次交给HeadFilter->user-defined-IoFilters->TailFilter来处理这些事件,例如exceptionCaught,messageReceived,SessionIdle等等。这些调用最后会调用IoHandler里面的对应事件函数。同样的,IoHandler里面的输出,例如messageReceived里面如果要输出信息,使用session.write("my message")这样,那么其实就会逆着这个图往上走,依次经过FilterChain(TailFilter->user-defined-IoFilter->HeadFilter)然后到session调用它的processor去控制channel写出。

mina使用

mina的使用其实参考官方的那个例子就可以了,我目前也只是照着画了一遍葫芦。
mina Server

  1. package com.alan.server;
  2. import java.io.IOException;
  3. import java.net.InetSocketAddress;
  4. import java.nio.charset.Charset;
  5. import org.apache.mina.core.service.IoAcceptor;
  6. import org.apache.mina.core.session.IdleStatus;
  7. import org.apache.mina.filter.codec.ProtocolCodecFilter;
  8. import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
  9. import org.apache.mina.filter.logging.LoggingFilter;
  10. import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
  11. import org.slf4j.Logger;
  12. import org.slf4j.LoggerFactory;
  13. import org.apache.log4j.BasicConfigurator;
  14. public class MinaServer {
  15. private static final Logger LOG = LoggerFactory.getLogger(MinaServer.class);
  16. private static final int PORT=9123;
  17. public static void main(String[] args) throws IOException{
  18. BasicConfigurator.configure(); //这里使用了sl4j这个抽象的日志库,它其实就是给各种log库实现了一个适配器模式,根据实际的场景很容易切换不同的日志库。依赖log4j,sl4j-api,sl4j-log4j这三个库。log4j默认没有配置文件,需要自己写一个日志文件,或者使用BasicConfigurator
  19. IoAcceptor acceptor = new NioSocketAcceptor(); //基于java nio的IoService,也就是所谓的server
  20. acceptor.getFilterChain().addLast("logger", new LoggingFilter()); //添加日志记录过滤器
  21. acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));
  22. //添加编码解码的过滤器
  23. acceptor.setHandler(new TimeServerHandler()); //TimeServerHandler就是IoHandler,具体的事件处理程序,开发者需要实现它已有的一些方法接口函数
  24. acceptor.getSessionConfig().setReadBufferSize(2048); //设置读取的buffer缓存大小
  25. acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10); //设置判断会话是否空闲的阈值
  26. acceptor.bind(new InetSocketAddress(PORT)); //绑定到特定端口,然后这个bind最后就会调用startupAcceptor处理请求...
  27. LOG.info("Server started...");
  28. }
  29. }

IoHandler-事件的处理

  1. package com.alan.server;
  2. import java.util.Date;
  3. import org.apache.mina.core.service.IoHandlerAdapter;
  4. import org.apache.mina.core.session.IdleStatus;
  5. import org.apache.mina.core.session.IoSession;
  6. import org.slf4j.Logger;
  7. import org.slf4j.LoggerFactory;
  8. public class TimeServerHandler extends IoHandlerAdapter{
  9. private static final Logger LOG= LoggerFactory.getLogger(TimeServerHandler.class);
  10. //发生异常后的事件处理函数
  11. @Override
  12. public void exceptionCaught(IoSession session, Throwable cause) throws Exception{
  13. cause.printStackTrace();
  14. }
  15. @SuppressWarnings("deprecation")
  16. //消息接收到后的事件处理函数
  17. @Override
  18. public void messageReceived(IoSession session, Object message) throws Exception
  19. {
  20. String str = message.toString();
  21. if (str.trim().equalsIgnoreCase("quit")){
  22. session.close();
  23. return;
  24. }
  25. Date date = new Date();
  26. session.write(date.toString());
  27. LOG.info("Message written...");
  28. }
  29. //会话空闲的事件处理函数,一般是idlecheck的时候发现距离上次idle check time或者iotime超过了判断是否空闲的阈值时间那么就会触发这个事件
  30. @Override
  31. public void sessionIdle(IoSession session, IdleStatus status) throws Exception
  32. {
  33. LOG.info("IDLE" + session.getIdleCount(status));
  34. }
  35. }

通过 telnet ip port就可以连接并且发送接收消息,当然也可以自行编写java版的mina client。
下一篇想写一部分mina的源码的大概分析,更加深入了解mina的工作流程

0 0
原创粉丝点击