Mina2源码分析

合集下载

Mina2.0工作原理以及配置注意事项

Mina2.0工作原理以及配置注意事项
3.基于 Mina 的应用程序的开发步骤
接上节,介绍基于 mina 开发的一般步骤: 简单的 TCPServer 第一步:编写 IoService 按照上面的执行流程,我们首先需要编写 IoService,IoService 本身既是服
务端,又是客户端,我们这里编写服务端,所以使用 IoAcceptor 实现,由于 IoAcceptor 是 与 协 议 无 关 的 , 因 为 我 们 要 编 写 TCPServer , 所 以 我 们 使 用 IoAcceptor 的 实 现 NioSocketAcceptor , 实 际 上 底 层 就 是 调 用 java.nio.channels.ServerSocketChannel 类。当然,如果你使用了 Apache 的 APR 库,那么你可以选择使用 AprSocketAcceptor 作为 TCPServer 的实现,据传说 Apache APR 库的性能比 JVM 自带的本地库高出很多。 IoProcessor 是由指定的 IoService 内部创建并调用的,我们并不需要关心。 public class MyServer {
private final static Logger log = LoggerFactory .getLogger(MyIoHandler.class);
@Override public void messageReceived(IoSession session, Object message)
(3) IoFilter:这个接口定义一组拦截器,这些拦截器可以包括日志输出、黑
名单过滤、数据的编码(write 方向)与解码(read 方向)等功能,其中数据的 encode 与 decode 是最为重要的、也是你在使用 Mina 时最主要关注的地方。

MINA

MINA

APACHE MINA 介绍一个高性能的NIO框架•MINA 的用途•MINA 选择MINA的理由•MINA 的快速入门•MINA 的高级话题讲座目标背景,用途以及所支持的功能的一个简略介绍,让大家认识MINA,对它有个初步概念。

这就是本章的目的。

在java世界中,框架繁多,就网络框架而言,我们为什么要选择MINA2这确实值得我们探讨一下。

下面的小节中将本着对软件开发最基本的两点出发进行对比:1.性能的对比2.程序实现的复杂性对比在传统I/O中,最简单实现高并发服务器的编程方式就是对每一个客户开启一个线程。

但是这种方式有如下几个弊端:•客户端上限很大的情况下不能及时响应•服务器硬件资源受限,性能也会急剧下降•受制于操作系统的限制优点还是有的:•编码简单,实现容易•一定数量的连接性能比较好。

参见实例:TraditionalIOServer0从图中可见,每一个线程维护了一组用户,然后每一个线程不断的轮询用户,哪个用户可读就读取相应的可读字节数,也就是这种方式避免了读的阻塞。

但是这种方式是一种被动的方式,也就是说不管用户是否可读,都需要去轮询。

为了解决这一问题,异步的NIO就成了不二之选选择MINA的理由NIO简单介绍JDK1.4提供的无阻塞I/O(NIO)有效解决了多线程服务器存在的线程开销问题,又同时避免了轮询问题,但在使用上略显得复杂一些。

NIO的核心思想就是多路复用,与模型二类似。

但是它是基于事件机制,所以这就是能避开轮询的原因。

但是需要注意的是,他们本质上是不同的,模型二只能算是一个模拟的多路复用,而NIO则是利用OS底层以及一些别的技术来达到异步多路复用的目的。

看完几个实际的MINA例子后可以很轻易的总结出利用MINA编程的几个大致步骤:1.创建一个实现了IoService接口的类2.设置一个实现了IoFilter接口的过滤器(如果有需要的情况下)3.设置一个IoHandler接口实现的处理类,用于处理事件(必须)4.对IoService绑定一个端口开始工作IoProcessor是处理请求的分配,包括选择Selector,超时验证,状态记录等。

mina编码器详解

mina编码器详解
numberOfCharachters); out.write(request); return true;
} else { return false;
} } }
注意: . 每当一条完整的消息需要被解码时,就把它写入 ProtocolDecoderOutput 中;这 些消息将沿着过滤器链,并最终到达 IoHandler 类的 messageReceived(IoSession session, Object message)方法 . 你没必要去释放 IoBuffer。 . 当没有足够的数据用来解码成一条消息,就返回 false。
概述一下我们需要的编解码请求和响应类:
. ImageRequest:一个简单 POJO,表示向服务端的请求。 . ImageRequestEncoder:将请求对象编码成特定协议的数据(客户端使用) . ImageRequestDecoder:将特定协议的数据解码成请求对象(服务端使用) . ImageResponse:一个简单 POJO,表示来自服务端的响应。 . ImageResponseEncoder:服务端用来编码响应对象。 . ImageResponseDecoder:客户端用来解码响应对象。 . ImageCodecFactory:这个类用来创建必要的编码器和解码器。
public void dispose(IoSession session) throws Exception { // nothing to dispose
} }
注意: . MINA 对 IoSession 写队列中的所有消息调用编码方法。因此客户端只需写入请 求对象,该请求对象由消息强制转化得到。 . 从堆内存中分配一个新的 IoBuffer,最好避免使用直接缓冲区,因为一般情况 下堆缓冲区有更好的表现。参考 /jira/browse/DIRMINA-289 . 没有必要释放缓冲区,MINA 将自动释放使用完的缓冲区。参考 http:// /report/trunk/apidocs/org /apache/mina/ common/I oBuffer.h

p2p技术之n2n源码核心简单分析一

p2p技术之n2n源码核心简单分析一

p2p技术之n2n源码核⼼简单分析⼀⾸先在开篇之前介绍下内⽹打洞原理场景:⼀个服务器S1在公⽹上有⼀个IP,两个私⽹机器C1,C2C1,C2分别由NAT1和NAT2连接到公⽹,我们需要借助S1将C1,C2建⽴直接的TCP连接,即由C1向C2打⼀个洞,让C2可以沿这个洞直接连接到C1主机,也就成了局域⽹访问的模式。

实现过程如下:1. S1启动两个⽹络监听(主连接监听,打洞监听)2. 由于S1是公⽹,所以C1,C2和S1保持通信,3. 当C1需要和C2建⽴直接的TCP连接时,⾸先连接S1的打洞监听端⼝,并发给S1请求协助连接C2的申请,同时在该端⼝号上启动侦听,记得套接字设置允许重⼊SO_REUSEADDR 属性,否则侦听会失败4. S1监听打洞端⼝收到请求后通知C2,并将C1经过NAT1转换的公⽹IP地址和端⼝等信息告诉C25. C2收到S1的连接通知后⾸先与S1的打洞端⼝连接,随便发送⼀些数据后⽴即断开(原因:让S1知道C2经过NAT-2转换后的公⽹IP和端⼝号)6. C2试着连接到C1(经过NAT1转换后的公⽹IP地址和端⼝),⼤多数路由器对于不请⾃到的SYN请求包直接丢弃⽽导致连接失败,但NAT1会纪录此次连接的源地址和端⼝号,为接下来真正的连接做好了准备,这就是所谓的打洞,即C2向C1打了⼀个洞,下次C1就能直接连接到C2刚才使⽤的端⼝号7. 客户端C2打洞的同时在相同的端⼝上启动侦听。

C2在⼀切准备就绪以后通过与S1的主连接监听端⼝回复消息“我准备好了”,S1在收到以后将C2经过NAT2转换后的公⽹IP和端⼝号告诉给C18. C1收到S1回复的C2的公⽹IP和端⼝号等信息以后,开始连接到C2公⽹IP和端⼝号,由于在步骤6中C2曾经尝试连接过C1的公⽹IP地址和端⼝,NAT1纪录了此次连接的信息,所以当C1主动连接C2时,NAT2会认为是合法的SYN数据,并允许通过,从⽽直接的TCP 连接建⽴起来了n2n项⽬开源地址:/ntop/n2n其实现核⼼是利⽤虚拟⽹卡巧妙实现了⽹络隧道的封装,只利⽤了tap设备,实⽤twofish加密接⼝lzo数据压缩实现了内⽹通讯。

读书摘要观后感与总结:《Glibc内存管理:ptmalloc2源代码分析》

读书摘要观后感与总结:《Glibc内存管理:ptmalloc2源代码分析》

读书摘要观后感与总结:《Glibc内存管理:ptmalloc2源代码分析》更新中在Linux平台下做漏洞利⽤的时候,针对于Heap部分总是有些不求甚解,下⾯开个博⽂来记录下《Glibc内存管理:ptmalloc2源代码分析》这本书的读后感和收获,⼀些简单的点将不再记录说明,本博⽂中所有的实验均在Linux Ubuntu16.04的环境下进⾏⽬录树:⼀些关于计算size的宏"chunk to mem" and "mem to chunk"about size分箱式内存管理smallbinslargebins⼀些关于计算size的宏Ptmalloc设计的时候很巧妙的⼀点就是利⽤宏来屏蔽不同平台的差异,⼀些简单的细节⽐如chunk的形式在此我就不再赘述,下⾯记录⼀下读后有收获的点"chunk to mem" and "mem to chunk"/* conversion from malloc headers to user pointers, and back */#define chunk2mem(p) ((void*)((char*)(p) + 2*SIZE_SZ))#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ))about sizeMIN_CHUNK_SIZE定义了最⼩的chunk⼤⼩,MINSIZE定义了最⼩的分配的内存⼤⼩,是对MIN_CHUNK_SIZE进⾏了2*SIZE_SZ对齐,对齐后与MIN_CHUNK_SIZE的⼤⼩仍然是⼀样的/* The smallest possible chunk */#define MIN_CHUNK_SIZE (offsetof(struct malloc_chunk, fd_nextsize))/* The smallest size we can malloc is an aligned minimal chunk */#define MINSIZE \(unsigned long)(((MIN_CHUNK_SIZE+MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK))下⾯说明⼀下chunk是如何计算其size的/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */#define PREV_INUSE 0x1/* extract inuse bit of previous chunk */#define prev_inuse(p) ((p)->mchunk_size & PREV_INUSE)/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */#define IS_MMAPPED 0x2/* check for mmap()'ed chunk */#define chunk_is_mmapped(p) ((p)->mchunk_size & IS_MMAPPED)/* size field is or'ed with NON_MAIN_ARENA if the chunk was obtainedfrom a non-main arena. This is only set immediately before handingthe chunk to the user, if necessary. */#define NON_MAIN_ARENA 0x4#define SIZE_BITS (PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)/* Like chunksize, but do not mask SIZE_BITS. */#define chunksize_nomask(p) ((p)->mchunk_size)/* Get size, ignoring use bits */#define chunksize(p) (chunksize_nomask (p) & ~(SIZE_BITS))/* Ptr to next physical malloc_chunk. */#define next_chunk(p) ((mchunkptr) (((char *) (p)) + chunksize (p)))/* Size of the chunk below P. Only valid if !prev_inuse (P). */#define prev_size(p) ((p)->mchunk_prev_size)⽐如做个实验来验证下,我们的chunksize为0x71,那么它本⾝的真实size是如何计算的?根据宏定义来计算可以看到计算得出的结果显然正确下⾯这⼀组宏定义⽤来check/set/clear当前chunk使⽤标志位,有当前chunk的使⽤标志位存储在下⼀个chunk的size的P位,所以下⾯的宏都要⾸先算出来下⼀个chunk的地址然后再做处理/* extract p's inuse bit */#define inuse(p) \((((mchunkptr) (((char *) (p)) + chunksize (p)))->mchunk_size) & PREV_INUSE)/* set/clear chunk as being inuse without otherwise disturbing */#define set_inuse(p) \((mchunkptr) (((char *) (p)) + chunksize (p)))->mchunk_size |= PREV_INUSE#define clear_inuse(p) \((mchunkptr) (((char *) (p)) + chunksize (p)))->mchunk_size &= ~(PREV_INUSE)我们可以简单来实验⼀下define inuse(p) 定义p的inusedefine set_inuse(p) 设置p的inuse位(p的nextchuhnk来设置)define clear_inuse(p) 清理p的inuse位下⾯三个宏⽤来check/set/clear指定chunk的size域中的使⽤标志位/* check/set/clear inuse bits in known places */#define inuse_bit_at_offset(p, s) \(((mchunkptr) (((char *) (p)) + (s)))->mchunk_size & PREV_INUSE)#define set_inuse_bit_at_offset(p, s) \(((mchunkptr) (((char *) (p)) + (s)))->mchunk_size |= PREV_INUSE)#define clear_inuse_bit_at_offset(p, s) \(((mchunkptr) (((char *) (p)) + (s)))->mchunk_size &= ~(PREV_INUSE))分箱式内存管理smallbinssmallbins有64个bin,实际共62个bin,bin[0]和bin[1]不存在chunk_size = 2 * SIZE_SZ * index范围:16B-504B (32B-1008B)ptmalloc维护了62个双向环形链表,每个链表都有头节点,便于管理,每个链表内各个空闲的chunk的⼤⼩⼀致largebins32:⼤于等于512B64:⼤于等于1024B⼀共63个bins每个bin中的chunk⼤⼩不是⼀个固定公差的等差数列,⽽是分成6组bin,每组bin是⼀个固定公差的等差数列每组的bin数量依次为:32,16, 8, 4, 2, 1公差依次为: 64,512,4096,32768,262144可以⽤数学来描述计算largebins的chunk_size第⼀组:chunksize = 512 + 64 * index第⼆组:chunksize = 512 + 64 * 32 + 512 * index……可以看到,其实smallbins和largebins差不多满⾜同样的规律,所以可以将small bins和large bins放在同⼀个包含128个chunk的数组上,数组前⼀部分为small bins,后⼀部分为large bins。

llama2源码解读

llama2源码解读

llama2源码解读llama2是一个开源的项目,它是一个用C++编写的高性能计算库,主要用于处理大规模的图形数据。

llama2的源码包含了许多复杂的算法和数据结构,因此需要深入的解读才能完全理解其内部工作原理。

首先,让我们从llama2的整体架构开始解读。

llama2的源码主要包括了图数据结构的表示和操作、图算法的实现、以及与底层硬件和系统交互的部分。

在图数据结构方面,llama2采用了一种高效的压缩存储方式,以节省内存空间并提高数据访问速度。

在图算法方面,llama2实现了许多常见的图算法,比如最短路径算法、连通分量算法等。

此外,llama2还利用了现代计算机体系结构的特性,比如多核并行、向量化指令等,以提高算法的执行效率。

接下来,让我们深入分析llama2源码中的关键部分。

在图数据结构的表示和操作方面,llama2使用了一种基于压缩的邻接表表示方法,以及一种基于稀疏矩阵的方式来存储图的属性信息。

这些数据结构的实现涉及了许多复杂的数据压缩和解压缩算法,以及高效的数据访问方法。

在图算法的实现方面,llama2采用了现代的并行计算技术,比如多线程并行、SIMD指令并行等,以加速算法的执行。

此外,llama2还使用了一些高级的优化技术,比如内存预取、数据局部性优化等,以进一步提高算法的性能。

最后,让我们讨论一下llama2源码的未来发展方向。

随着大规模图数据处理的需求不断增长,llama2的源码将会不断演进和完善。

未来的llama2源码可能会加入更多的图算法实现、更高效的数据压缩算法、以及更多针对特定硬件和系统的优化。

同时,llama2的源码也将会更加注重可移植性和扩展性,以便在不同的计算环境中得到更好的性能表现。

总之,llama2的源码是一个非常复杂和丰富的项目,需要深入的解读才能完全理解其内部工作原理。

通过对llama2源码的全面解读,我们可以更好地理解大规模图数据处理的挑战和解决方案,从而为未来的图计算技术发展做出更大的贡献。

MINA2实用手册

MINA2实用手册

MINA2实用手册作者:李庆丰Email:scholers@MINA框架是对java的NIO包的一个封装,简化了NIO程序开发的难度,封装了很多底层的细节,然开发者把精力集中到业务逻辑上来,最近做了一个相关的项目,为了备忘对MINA做一个总结。

一、服务端初始化及参数配置MINA2初始化很简单。

基本的初始化参数如下://初始化Acceptor—可以不指定线程数量,MINA2里面默认是CPU数量+2 NioSocketAcceptor acceptor = new NioSocketAcceptor(5);java.util.concurrent.Executor threadPool =Executors.newFixedThreadPool(1500);//建立线程池//加入过滤器(Filter)到Acceptoracceptor.getFilterChain().addLast("exector", newExecutorFilter(threadPool));//编码解码器acceptor.getFilterChain().addLast("codec",new ProtocolCodecFilter(new WebDecoder(),newXmlEncoder()));//日志LoggingFilter filter = new LoggingFilter();filter.setExceptionCaughtLogLevel(LogLevel.DEBUG);filter.setMessageReceivedLogLevel(LogLevel.DEBUG);filter.setMessageSentLogLevel(LogLevel.DEBUG);filter.setSessionClosedLogLevel(LogLevel.DEBUG);filter.setSessionCreatedLogLevel(LogLevel.DEBUG);filter.setSessionIdleLogLevel(LogLevel.DEBUG);filter.setSessionOpenedLogLevel(LogLevel.DEBUG);acceptor.getFilterChain().addLast("logger", filter);acceptor.setReuseAddress(true);//设置的是主服务监听的端口可以重用acceptor.getSessionConfig().setReuseAddress(true);//设置每一个非主监听连接的端口可以重用MINA2中,当启动一个服务端的时候,要设定初始化缓冲区的长度,如果不设置这个值,系统默认为2048,当客户端发过来的消息超过设定值的时候,MINA2的机制是分段接受的,将字符是放入缓冲区中读取,所以在读取消息的时候,需要判断有多少次。

Mina2.0快速入门与源码剖析

Mina2.0快速入门与源码剖析

第 1页
共 38页
Mina2.0 快速入门与源码剖析
1. Mina2.0 快速入门
MinaTimeServer.java
package com.vista; import java.io.IOException; import .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 { //监听即将到来的 TCP 连接 IoAcceptor acceptor = new NioSocketAcceptor(); acceptor.getFilterChain().addLast("logger", new LoggingFilter()); acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter ( new TextLineCodecFactory( Charset.forName("UTF-8")))); acceptor.setHandler(new TimeServerHandler()); acceptor.getSessionConfig().setReadBufferSize(2048); acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10); acceptor.bind(new InetSocketAddress(PORT)); System.out.println("服务器启动"); } }
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Mina2.0框架源码剖析(一)整个框架最核心的几个包是:org.apache.mina.core.service,org.apache.mina.core.session, org.apache.mina.core.polling以及org.apache.mina.transport.socket。

这一篇先来看org.apache.mina.core.service。

第一个要说的接口是IoService,它是所有IoAcceptor和IoConnector的基接口.对于一个IoService,有哪些信息需要我们关注呢?1)底层的元数据信息TransportMetadata,比如底层的网络服务提供者(NIO,ARP,RXTX等),2)通过这个服务创建一个新会话时,新会话的默认配置IoSessionConfig。

3)此服务所管理的所有会话。

4)与这个服务相关所产生的事件所对应的监听者(IoServiceListener)。

5)处理这个服务所管理的所有连接的处理器(IoHandler)。

6)每个会话都有一个过滤器链(IoFilterChain),每个过滤器链通过其对应的IoFilterChainBuilder来负责构建。

7)由于此服务管理了一系列会话,因此可以通过广播的方式向所有会话发送消息,返回结果是一个WriteFuture集,后者是一种表示未来预期结果的数据结构。

8)服务创建的会话(IoSession)相关的数据通过IoSessionDataStructureFactory来提供。

9)发送消息时有一个写缓冲队列。

10)服务的闲置状态有三种:读端空闲,写端空闲,双端空闲。

11)还提供服务的一些统计信息,比如时间,数据量等。

IoService这个服务是对于服务器端的接受连接和客户端发起连接这两种行为的抽象。

再来从服务器看起,IoAcceptor是IoService 的子接口,它用于绑定到指定的ip和端口,从而接收来自客户端的连接请求,同时会fire相应的客户端连接成功接收/取消/失败等事件给自己的IoHandle去处理。

当服务器端的Accpetor从早先绑定的ip和端口上取消绑定时,默认是所有的客户端会话会被关闭,这种情况一般出现在服务器挂掉了,则客户端收到连接关闭的提示。

这个接口最重要的两个方法是bind()和unbind(),当这两个方法被调用时,服务端的连接接受线程就启动或关闭了。

再来看一看客户端的连接发起者接口IoConnector,它的功能和IoAcceptor基本对应的,它用于尝试连接到服务器指定的ip和端口,同时会fire相应的客户端连接事件给自己的IoHandle去处理。

当connet方法被调用后用于连接服务器端的线程就启动了,而当所有的连接尝试都结束时线程就停止。

尝试连接的超时时间可以自行设置。

Connect方法返回的结果是ConnectFuture,这和前面说的WriteFuture类似,在后面会有一篇专门讲这个模式的应用。

前面的IoAcceptor和IoConnector就好比是两个负责握手的仆人,而真正代表会话的实际I/O操作的接口是IoProcessor,它对现有的Reactor模式架构的Java NIO框架继续做了一层封装。

它的泛型参数指明了它能处理的会话类型。

接口中最重要的几个方法,add用于将指定会话加入到此Processor中,让它负责处理与此会话相关的所有I/O操作。

由于写操作会有一个写请求队列,flush就用于对指定会话的写请求队列进行强制刷数据。

remove方法用于从此Processor中移除和关闭指定会话,这样就可以关闭会话相关联的连接并释放所有相关资源。

updateTrafficMask方法用于控制会话的I/O行为,比如是否允许读/写。

然后来说说IoHandle接口,Mina中的所有I/O事件都是通过这个接口来处理的,这些事件都是上面所说的I/O Processor发出来的,要注意的一点是同一个I/O Processor线程是负责处理多个会话的。

包括下面这几个事件的处理:public interface IoHandler{void sessionCreated(IoSession session) throws Exception;//会话创建void sessionOpened(IoSession session) throws Exception;//打开会话,与sessionCreated最大的区别是它是从另一个线程处调用的void sessionClosed(IoSession session) throws Exception;//会话结束,当连接关闭时被调用void sessionIdle(IoSession session, IdleStatus status) throws Exc eption;//会话空闲void exceptionCaught(IoSession session, Throwable cause) throws E xception;//异常捕获,Mina会自动关闭此连接void messageReceived(IoSession session, Object message) throws Ex ception;//接收到消息void messageSent(IoSession session, Object message) throws Except ion;//发送消息}IoHandlerAdapter就不说了,简单地对IoHandler使用适配器模式封装了下,让具体的IoHandler子类从其继承后,从而可以对自身需要哪些事件处理拥有自主权。

来看看IoServiceListener接口,它用于监听IoService相关的事件。

public interface IoServiceListener extends EventListener{void serviceActivated(IoService service) throws Exception;//激活了一个新servicevoid serviceIdle(IoService service, IdleStatus idleStatus) throws Exception; // service闲置void serviceDeactivated(IoService service) throws Exception;//挂起一个servicevoid sessionCreated(IoSession session) throws Exception;//创建一个新会话void sessionDestroyed(IoSession session) throws Exception;//摧毁一个新会话}IoServiceListenerSupport类就是负责将上面的IoService和其对应的各个IoServiceListener包装到一起进行管理。

下面是它的成员变量:private final IoService service;private final List<IoServiceListener> listeners = new CopyOnWrite ArrayList<IoServiceListener>();private final ConcurrentMap<Long, IoSession> managedSessions = ne w ConcurrentHashMap<Long, IoSession>();//被管理的会话集(其实就是服务所管理的会话集)private final Map<Long, IoSession> readOnlyManagedSessions = Coll ections.unmodifiableMap(managedSessions);//上面的会话集的只读版private final AtomicBoolean activated = new AtomicBoolean();//被管理的服务是否处于激活状态激活事件就以会话创建为例来说明:public void fireSessionCreated(IoSession session){boolean firstSession = false;if (session.getService() instanceof IoConnector){//若服务类型是Connector,则说明是客户端的连接服务synchronized (managedSessions){//锁住当前已经建立的会话集firstSession = managedSessions.isEmpty();//看服务所管理的会话集是否为空集}}if (managedSessions.putIfAbsent(Long.valueOf(session.g etId()), session) != null) { // If already registered, ignore.return;}if (firstSession){//第一个连接会话,fire一个虚拟的服务激活事件fireServiceActivated();}//呼叫过滤器的事件处理session.getFilterChain().fireSessionCreated();// 会话创建session.getFilterChain().fireSessionOpened();//会话打开int managedSessionCount = managedSessions.size();//统计管理的会话数目if (managedSessionCount > largestManagedSessionCount){largestManagedSessionCount = managedSessionCount;}cumulativeManagedSessionCount ++;//呼叫监听者的事件处理函数for (IoServiceListener l : listeners){try{l.sessionCreated(session);} catch (Throwable e){ExceptionMonitor.getInstance().exceptionCaught(e); }}}这里值得注意的一个地方是断开连接会话,设置了一个监听锁,直到所有连接会话被关闭后才放开这个锁。

private void disconnectSessions(){if (!(service instanceof IoAcceptor)){//确保服务类型是IoAcceptorreturn;}if (!((IoAcceptor) service).isCloseOnDeactivation()){// IoAcceptor是否设置为在服务失效时关闭所有连接会话return;}Object lock = new Object();//监听锁IoFutureListener<IoFuture> listener = new LockNotifyingListen er(lock);for (IoSession s : managedSessions.values()){s.close().addListener(listener);//为每个会话的close动作增加一个监听者}try{synchronized (lock){while (!managedSessions.isEmpty()){//所管理的会话还没有全部结束,持锁等待lock.wait(500);}}} catch (InterruptedException ie){// Ignored}}private static class LockNotifyingListener implements IoFutureLis tener<IoFuture>{private final Object lock;public LockNotifyingListener(Object lock){this.lock = lock;}public void operationComplete(IoFuture future){synchronized (lock){lock.notifyAll();}}}Mina2.0框架源码剖析(二)上一篇介绍了几个核心的接口,这一篇主要介绍实现这些接口的抽象基类。

相关文档
最新文档