免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3418 | 回复: 0
打印 上一主题 下一主题

mina 1.1.7 源码阅读笔记 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-06-20 22:39 |只看该作者 |倒序浏览
    以前从来没有接触过java,一个偶然的机会,知道apache的开源项目中有个高性能的网络框架。(如果直接照搬到c/c++的话,里面则有很多地方需要优化,特别是内存拷贝,因为java对字符串的复制做了优化,即如果字符串本身没有修改的话,里面的内容仅仅是对源的引用,而不是复制。)
    一般情况下,使用者仅仅需要关心下面几个接口:
    IoAcceptor:  提供对套接字监听的封装
    IoConnector: 提供对套接字连接的封装
    IoSession:   提供对套接字读、写、关闭的封装
    IoFilter:    提供多虑连的封装。这个是mina比较赞的地方。通过过滤链,mina可以实现多层复杂协议的解析。例如如果要一个DCOM代理。而DCOM的底层协议是DCE-RPC协议,然后在135端口中的stub部分,使用了特殊的IDL定义的stub数据。进行协议解析是,对协议的解码分层,业务逻辑的分离,对于实现都是十分有利的。IoFilter甚至可以提供对线程模型的定义。在默认情况下,mina的业务逻辑和套接字的读写是在同一个线程中进行的。

    一、java中的nio
    nio是java中一种高效的异步IO模型。在nio中,所有的套接字都是属于channel(具体的类名我就写了,不管是用于listen,accept还是connect的,这里都称之为channel。),每个channel都包含了一个被称之为selectkey的类,每个selectkey同样被包含其对应的channel。
    在selector中,有若干个selectkey队列,register_queue、cannel_queue等(这些名字都是我为了方便自己定的,在java源码中肯定不是这样)。所有新注册的、被修改的key,都会在调用selector.select()之前被新增或修改到一个类似epoll的东西里面去,然后在事件返回之后,处理cannel_queue中的已经被取消的key,并释放相关资源。
    mina的SocketIoAcceptor、SocketIoConnector、SocketIoProcessor中也全部采用了类似的模式。这种模式的优点是可以叫好的处理在多线程环境中新增、修改、删除套接字事件。不过我感觉应该只能在一个线程中调用selector.select(),否则荣誉出问题。

    二、SocketIoAcceptor
    SocketIoAcceptor是IoAcceptor的一个实现。SocketIoAcceptor同一时刻有且仅有一个工作线程,并且该工作线程会在没有任何套接字的情况下退出线程。但是,SocketIoProcessor可以有多个IoProcessor工作线程。
    几个重要流程如下:
    1.bind() 函数
      必要时创建线程 -> 把需要bind的地址加入register队列 -> 唤醒selector -> 等待bind完成
    2.unbind 函数
      必要时创建线程 -> 把需要unbind的地址加入cancel队列 -> 唤醒selector -> 等待unbind完成
    3.工作线程Worker
      无限期等待selector返回 -> 依次bind register队列中的地址并加入selector,同时将其从队列中移除 -> 依次处理selector返回的key,然后把套接字按照轮流的方式分发到不同的IoProcessor中,并根据结果触发事件 -> 依次从cancel队列中,关闭对应的套接字,然后唤醒selector(这里唤醒应该因为调用key.cancel并没有真正的取消,而是在下次selector.select()返回之后才执行的。如果不唤醒,那么有可能这些资源永远没有被释放掉)-> 唤醒bind/unbind的等待 ->如果有必要,退出线程。

    三、SocketIoConnector
    SocketIoConnector是IoConnector的一个实现。流程等各方面大致一样,就懒得写了。

    四、SocketIoProcessor
    SocketIoProcessor是IoProcessor的一个实现。该类是套接字收发的工作线程。一旦套接字加入某个线程中,就永远只会在这个线程进行数据收发。在IoAccepotr和IoConnector的工作线程中,selector.select()总是无限期的等待,而这里则是带超时的(1秒). 因为在remove的时候,并没有唤醒线程,而且通过超时使得其最迟在以后的1秒内完成动作。因为一般来说,关闭事件总是不那么紧急。
    几个重要流程如下:
    1、addNewSession、RemoveSession、UpdateTrafficMask流程大致一致:
      加入对应的队列 -> 必要时唤醒工作线程 -> 唤醒selector(RemoveSession除外)
    2.工作线程Worker
      调用selector.select(1000) -> 依次注册newSessions队列的套接字,并监听可读事件,然后将其从中移除 -> 依次从更新trafficControllingSessions队列中的套接字事件,并且根据套接字的关闭、发送队列等标识进行更新(例如:如果没有发送队列,则强制移除写事件) -> 依次处理返回的key,根据当前监听的时间标识进行数据的接收并触发相应事件或者加入flushingSessions队列 -> 依次对flushingSessions中的session执行写操作并触发相应事件 -> 依次把removingSessions队列的套接字从selector中移除并关闭,同时也从flushingSessions队列中移除,触发相应事件-> 检查所有session的读写空闲,并触发相应事件。-> 如有必要,退出线程.

    五、mina对于提升性能、保证多线程环境中的使用、以及资源控制的几点努力
    1. nio和mina一样,都使用了队列以及延后处理,单个工作线程的方式,来实现外部接口可以再多线程环境中较自由的使用。
    2. 在mina 2.0中还实现了DefaultIoEventSizeEstimator来控制事件数量,防止高负载的服务器内存被事件撑爆。

     六、mina 2.0中的线程模型。
    (待续。。。)

   





本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/60481/showart_1971894.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP