Apache Mina Server 2.0 中文参考手册 【笔记】

#Apache Mina Server 2.0 中文参考手册
##3. 介绍Mina的TCP的主要接口:java

###(1.)IoService:
这个接口是服务端IoAcceptor、客户端IoConnector 的抽象,提供IO 服务和管理IoSession 的功能,它有以下几个经常使用的方法:缓存

A. TransportMetadata getTransportMetadata():

这个方法获取传输方式的元数据描述信息,也就是底层到底基于什么的实现,譬如:nio、 apr 等。安全

B. void addListener(IoServiceListener listener):

这个方法能够为IoService 增长一个监听器,用于监听IoService 的建立、活动、失效、空 闲、销毁,具体能够参考IoServiceListener 接口中的方法,这为你参与IoService 的生命 周期提供了机会。session

C. void removeListener(IoServiceListener listener):

这个方法用于移除上面的方法添加的监听器。异步

D. void setHandler(IoHandler handler):

这个方法用于向IoService 注册IoHandler,同时有getHandler()方法获取Handler。ide

E. Map<Long,IoSession> getManagedSessions():

这个方法获取IoService 上管理的全部IoSession,Map 的key 是IoSession 的id。性能

F. IoSessionConfig getSessionConfig():

这个方法用于获取IoSession 的配置对象,经过IoSessionConfig 对象能够设置Socket 连 接的一些选项。ui


###(2.)IoAcceptor:
这个接口是TCPServer 的接口,主要增长了void bind()监听端口、void unbind()解除对 套接字的监听等方法。这里与传统的JAVA 中的ServerSocket 不一样的是IoAcceptor 能够多 次调用bind()方法(或者在一个方法中传入多个SocketAddress 参数)同时监听多个端口。编码


###(3.)IoConnector:
这个接口是TCPClient 的接口, 主要增长了ConnectFuture connect(SocketAddress remoteAddress,SocketAddress localAddress)方法,用于与Server 端创建链接,第二个参 数若是不传递则使用本地的一个随机端口访问Server 端。这个方法是异步执行的,一样的, 也能够同时链接多个服务端。线程

###(4.)IoSession:
这个接口用于表示Server 端与Client 端的链接,IoAcceptor.accept()的时候返回实例。 这个接口有以下经常使用的方法:

A. WriteFuture write(Object message):

这个方法用于写数据,该操做是异步的。

B. CloseFuture close(boolean immediately):

这个方法用于关闭IoSession,该操做也是异步的,参数指定true 表示当即关闭,不然就 在全部的写操做都flush 以后再关闭。

C. Object setAttribute(Object key,Object value):

这个方法用于给咱们向会话中添加一些属性,这样能够在会话过程当中均可以使用,相似于 HttpSession 的setAttrbute()方法。IoSession 内部使用同步的HashMap 存储你添加的自 定义属性。

D. SocketAddress getRemoteAddress():

这个方法获取远端链接的套接字地址。

E. void suspendWrite():

这个方法用于挂起写操做,那么有void resumeWrite()方法与之配对。对于read()方法同 样适用。

F. ReadFuture read():

这个方法用于读取数据, 但默认是不能使用的, 你须要调用IoSessionConfig 的 setUseReadOperation(true)才可使用这个异步读取的方法。通常咱们不会用到这个方法, 由于这个方法的内部实现是将数据保存到一个BlockingQueue,假如是Server 端,由于大 量的Client 端发送的数据在Server 端都这么读取,那么可能会致使内存泄漏,但对于 Client,可能有的时候会比较便利。

G. IoService getService():

这个方法返回与当前会话对象关联的IoService 实例。 关于TCP链接的关闭: 不管在客户端仍是服务端,IoSession 都用于表示底层的一个TCP 链接,那么你会发现不管 是Server 端仍是Client 端的IoSession 调用close()方法以后,TCP 链接虽然显示关闭, 但 主线程仍然在运行,也就是JVM 并未退出,这是由于IoSession 的close()仅仅是关闭了TCP 的链接通道,并无关闭Server 端、Client 端的程序。你须要调用IoService 的dispose() 方法中止Server 端、Client 端。


###(5.)IoSessionConfig: 这个方法用于指定这次会话的配置,它有以下经常使用的方法:

A. void setReadBufferSize(int size):

这个方法设置读取缓冲的字节数,但通常不须要调用这个方法,由于IoProcessor 会自动调 整缓冲的大小。你能够调用setMinReadBufferSize()、setMaxReadBufferSize()方法,这 样不管IoProcessor 不管如何自动调整,都会在你指定的区间。

B. void setIdleTime(IdleStatus status,int idleTime):

这个方法设置关联在通道上的读、写或者是读写事件在指定时间内未发生,该通道就进入空 闲状态。一旦调用这个方法,则每隔idleTime 都会回调过滤器、IoHandler 中的sessionIdle() 方法。

C. void setWriteTimeout(int time):

这个方法设置写操做的超时时间。

D. void setUseReadOperation(boolean useReadOperation):

这个方法设置IoSession 的read()方法是否可用,默认是false。


(6.)IoHandler:

这个接口是你编写业务逻辑的地方,从上面的示例代码能够看出,读取数据、发送数据基本 都在这个接口总完成,这个实例是绑定到IoService 上的,有且只有一个实例(没有给一个 IoService 注入一个IoHandler 实例会抛出异常)。它有以下几个方法:

A. void sessionCreated(IoSession session):

这个方法当一个Session 对象被建立的时候被调用。对于TCP 链接来讲,链接被接受的时候 调用,但要注意此时TCP 链接并未创建,此方法仅表明字面含义,也就是链接的对象 IoSession 被建立完毕的时候,回调这个方法。 对于UDP 来讲,当有数据包收到的时候回调这个方法,由于UDP 是无链接的。

B. void sessionOpened(IoSession session):

这个方法在链接被打开时调用,它老是在sessionCreated()方法以后被调用。对于TCP 来 说,它是在链接被创建以后调用,你能够在这里执行一些认证操做、发送数据等。 对于UDP 来讲,这个方法与sessionCreated()没什么区别,可是紧跟其后执行。若是你每 隔一段时间,发送一些数据,那么sessionCreated()方法只会在第一次调用,可是 sessionOpened()方法每次都会调用。

C. void sessionClosed(IoSession session) :

对于TCP 来讲,链接被关闭时,调用这个方法。 对于UDP 来讲,IoSession 的close()方法被调用时才会毁掉这个方法。

D. void sessionIdle(IoSession session, IdleStatus status) :

这个方法在IoSession 的通道进入空闲状态时调用,对于UDP 协议来讲,这个方法始终不会 被调用。

E. void exceptionCaught(IoSession session, Throwable cause) :

这个方法在你的程序、Mina 自身出现异常时回调,通常这里是关闭IoSession。

F. void messageReceived(IoSession session, Object message) :

接收到消息时调用的方法,也就是用于接收消息的方法,通常状况下,message 是一个 IoBuffer 类,若是你使用了协议编解码器,那么能够强制转换为你须要的类型。一般咱们 都是会使用协议编解码器的, 就像上面的例子, 由于协议编解码器是 TextLineCodecFactory,因此咱们能够强制转message 为String 类型。

G. void messageSent(IoSession session, Object message) :

当发送消息成功时调用这个方法,注意这里的措辞,发送成功以后,也就是说发送消息是不 能用这个方法的。 发送消息的时机: 发送消息应该在sessionOpened()、messageReceived()方法中调用IoSession.write()方法 完成。由于在sessionOpened()方法中,TCP 链接已经真正打开,一样的在messageReceived() 方法TCP 链接也是打开状态,只不过二者的时机不一样。sessionOpened()方法是在TCP 链接 创建以后,接收到数据以前发送;messageReceived()方法是在接收到数据以后发送,你可 以完成依据收到的内容是什么样子,决定发送什么样的数据。 由于这个接口中的方法太多,所以一般使用适配器模式的IoHandlerAdapter,覆盖你所感 兴趣的方法便可。


(7.)IoBuffer:

这个接口是对JAVA NIO 的ByteBuffer 的封装,这主要是由于ByteBuffer 只提供了对基本 数据类型的读写操做,没有提供对字符串等对象类型的读写方法,使用起来更为方便,另外, ByteBuffer 是定长的,若是想要可变,将很麻烦。IoBuffer 的可变长度的实现相似于 StringBuffer。IoBuffer 与ByteBuffer 同样,都是非线程安全的。本节的一些内容若是不 清楚,能够参考java.nio.ByteBuffer 接口。 这个接口有以下经常使用的方法:

A. static IoBuffer allocate(int capacity,boolean useDirectBuffer):

这个方法内部经过SimpleBufferAllocator 建立一个实例,第一个参数指定初始化容量,第 二个参数指定使用直接缓冲区仍是JAVA 内存堆的缓存区,默认为false。

B. void free():

释放缓冲区,以便被一些IoBufferAllocator 的实现重用,通常没有必要调用这个方法,除 非你想提高性能(但可能未必效果明显)。

C. IoBuffer setAutoExpand(boolean autoExpand):

这个方法设置IoBuffer 为自动扩展容量,也就是前面所说的长度可变,那么能够看出长度 可变这个特性默认是不开启的。

D. IoBuffer setAutoShrink(boolean autoShrink):

这个方法设置IoBuffer 为自动收缩,这样在compact()方法调用以后,能够裁减掉一些没 有使用的空间。若是这个方法没有被调用或者设置为false,你也能够经过调用shrink() 方法手动收缩空间。

E. IoBuffer order(ByteOrder bo):

这个方法设置是Big Endian 仍是Little Endian,JAVA 中默认是Big Endian,C++和其余 语言通常是Little Endian。

F. IoBuffer asReadOnlyBuffer():

这个方法设置IoBuffer 为只读的。

G. Boolean prefixedDataAvailable(int prefixLength,int maxDataLength):

这个方法用于数据的最开始的一、二、4 个字节表示的是数据的长度的状况,prefixLentgh 表示这段数据的前几个字节(只能是一、二、4 的其中一个)的表明的是这段数据的长度, maxDataLength 表示最多要读取的字节数。返回结果依赖于等式 remaining()-prefixLength>=maxDataLength,也就是总的数据-表示长度的字节,剩下的字 节数要比打算读取的字节数大或者相等。

H. String getPrefixedString(int prefixLength,CharsetDecoder decoder):

若是上面的方法返回true,那么这个方法将开始读取表示长度的字节以后的数据,注意要 保持这两个方法的prefixLength 的值是同样的。 G、H 两个方法在后面讲到的PrefixedStringDecoder 中的内部实现使用。 IoBuffer 剩余的方法与ByteBuffer 都是差很少的,额外增长了一些便利的操做方法,例如: IoBuffer putString(String value,CharsetEncoder encoder)能够方便的以指定的编码方 式存储字符串、InputStream asInputStream()方法从IoBuffer 剩余的未读的数据中转为 输入流等。


###(8.)IoFuture: 在Mina 的不少操做中,你会看到返回值是XXXFuture,实际上他们都是IoFuture 的子类, 看到这样的返回值,这个方法就说明是异步执行的,主要的子类有ConnectFuture、 CloseFuture 、ReadFuture 、WriteFuture 。这个接口的大部分操做都和 java.util.concurrent.Future 接口是相似的,譬如:await()、awaitUninterruptibly() 等,通常咱们经常使用awaitUninterruptibly()方法能够等待异步执行的结果返回。 这个接口有以下经常使用的方法: ####A. IoFuture addListener(IoFutureListener<?> listener): 这个方法用于添加一个监听器, 在异步执行的结果返回时监听器中的回调方法 operationComplete(IoFuture future),也就是说,这是替代awaitUninterruptibly()方 法另外一种等待异步执行结果的方法,它的好处是不会产生阻塞。 ####B. IoFuture removeListener(IoFutureListener<?> listener): 这个方法用于移除指定的监听器。 ####C. IoSession getSession(): 这个方法返回当前的IoSession。 举个例子,咱们在客户端调用connect()方法访问Server 端的时候,实际上这就是一个异 步执行的方法,也就是调用connect()方法以后当即返回,执行下面的代码,而不论是否连 接成功。那么若是我想在链接成功以后执行一些事情(譬如:获取链接成功后的IoSession 对象),该怎么办呢?按照上面的说明,你有以下两种办法: 第一种:

ConnectFuture future = connector.connect(new InetSocketAddress(
HOSTNAME, PORT));
// 等待是否链接成功,至关因而转异步执行为同步执行。
future.awaitUninterruptibly();
// 链接成功后获取会话对象。若是没有上面的等待,因为connect()方法是异步的,session可能会没法获取。
session = future.getSession();

第二种:

ConnectFuture future = connector.connect(new InetSocketAddress(
HOSTNAME, PORT));
future.addListener(new IoFutureListener<ConnectFuture>() {
@Override
public void operationComplete(ConnectFuture future) {
try {
	Thread.sleep(5000);
} catch (InterruptedException e) {
	e.printStackTrace();
}
IoSession session = future.getSession();
System.out.println("++++++++++++++++++++++++++++");
}
});
System.out.println("*************");

为了更好的看清楚使用监听器是异步的,而不是像awaitUninterruptibly()那样会阻塞主 线程的执行,咱们在回调方法中暂停5 秒钟,而后输出+++,在最后输出***。咱们执行代码 以后,你会发现首先输出***(这证实了监听器是异步执行的),而后IoSession 对象Created, 系统暂停5 秒,而后输出+++,最后IoSession 对象Opened,也就是TCP 链接创建。


##4.日志配置: 前面的示例代码中提到了使用SLF4J 做为日志门面,这是由于Mina 内部使用的就是SLF4J, 你也使用SLF4J 能够与之保持一致性。 Mina 若是想启用日志跟踪Mina 的运行细节,你能够配置LoggingFilter 过滤器,这样你可 以看到Session 创建、打开、空闲等一系列细节在日志中输出,默认SJF4J 是按照DEBUG 级别输出跟踪信息的,若是你想给某一类别的Mina 运行信息输出指定日志输出级别,能够 调用LoggingFilter 的setXXXLogLevel(LogLevel.XXX)。 例:

LoggingFilter lf = new LoggingFilter();
lf.setSessionOpenedLogLevel(LogLevel.ERROR);
acceptor.getFilterChain().addLast("logger", lf);

这里IoSession 被打开的跟踪信息将以ERROR 级别输出到日志。


##5.过滤器: 前面咱们看到了LoggingFilter、ProtocolCodecFilter 两个过滤器,一个负责日志输出, 一个负责数据的编解码,经过最前面的Mina 执行流程图,在IoProcessor 与IoHandler 之 间能够有不少的过滤器,这种设计方式为你提供可插拔似的扩展功能提供了很是便利的方 式,目前的Apache CXF、Apache Struts2 中的拦截器也都是同样的设计思路。 Mina 中的IoFilter 是单例的,这与CXF、Apache Struts2 没什么区别。 IoService 实例上会绑定一个DefaultIoFilterChainBuilder 实例, DefaultIoFilterChainBuilder 会把使用内部的EntryImpl 类把全部的过滤器按照顺序连在 一块儿,组成一个过滤器链。 DefaultIoFilterChainBuilder 类以下经常使用的方法: ####A. void addFirst(String name,IoFilter filter): 这个方法把过滤器添加到过滤器链的头部,头部就是IoProcessor 以后的第一个过滤器。同 样的addLast()方法把过滤器添加到过滤器链的尾部。 ####B. void addBefore(String baseName,String name,IoFilter filter): 这个方法将过滤器添加到baseName 指定的过滤器的前面,一样的addAfter()方法把过滤器 添加到baseName 指定的过滤器的后面。这里要注意不管是那种添加方法,每一个过滤器的名 字(参数name)必须是惟一的。 ####C. IoFilter remove(Stirng name): 这个方法移除指定名称的过滤器,你也能够调用另外一个重载的remove()方法,指定要移除 的IoFilter 的类型。 ####D. List<Entry> getAll(): 这个方法返回当前IoService 上注册的全部过滤器。 默认状况下,过滤器链中是空的,也就是getAll()方法返回长度为0 的List,但实际Mina 内部有两个隐藏的过滤器:HeadFilter、TailFilter,分别在List 的最开始和最末端,很 明显,TailFilter 在最末端是为了调用过滤器链以后,调用IoHandler。但这两个过滤器对 你来讲是透明的,能够忽略它们的存在。 编写一个过滤器很简单,你须要实现IoFilter 接口,若是你只关注某几个方法,能够继承 IoFilterAdapter 适配器类。IoFilter 接口中主要包含两类方法,一类是与IoHandler 中的 方法名一致的方法,至关于拦截IoHandler 中的方法,另外一类是IoFilter 的生命周期回调 方法,这些回调方法的执行顺序和解释以下所示: (1.)init()在首次添加到链中的时候被调用,但你必须将这个IoFilter 用 ReferenceCountingFilter 包装起来,不然init()方法永远不会被调用。 (2.)onPreAdd()在调用添加到链中的方法时被调用,但此时还未真正的加入到链。 (3.)onPostAdd()在调用添加到链中的方法后被调,若是在这个方法中有异常抛出,则过滤 器会当即被移除,同时destroy()方法也会被调用(前提是使用ReferenceCountingFilter 包装)。 (4.)onPreRemove()在从链中移除以前调用。 (5.)onPostRemove()在从链中移除以后调用。 (6.)destory()在从链中移除时被调用,使用方法与init()要求相同。

相关文章
相关标签/搜索