http://www.cnblogs.com/ggzwtj/archive/2011/10/14/2212095.html
Mina之session
1、IoSession与底层的传输层类型无关,表示通信双端的连接。提供用户自定义属性,可以用于在过滤器和处理器之间交换用户自定义协议相关信息。每个会话都由一个Service来提供服务,同时有一个Handler负责此会话的I/O事件处理。最重要的两个方法就是read和write,这两个方法都是异步执行,如要真正完成必须在其结果上进行等待。关闭会话的方法close也是异步执行的,也就是应等待返回的CloseFuture,此外,还有另一种关闭方式closeOnFlush,它和close的区别是会先flush掉写请求队列中的请求数据,但同样是异步的。会话的读写类型是可配置的,在运行中可设置此端是否可读写。
一个会话主要包括两方面的数据:属性映射图和写请求队列,这里使用工厂模式来为新创建的会话提供这些数据结构,定义如下:
public interface IoSessionDataStructureFactory {
//返回属性
IoSessionAttributeMap getAttributeMap(IoSession session) throws Exception;
//返回写请求队列
WriteRequestQueue getWriteRequestQueue(IoSession session) throws Exception;
}
2、IoSessionConfig表示会话的配置信息,主要包括:读缓冲区大小,会话数据吞吐量,计算吞吐量的时间间隔,指定会话段的空闲时间,写请求操作超时时间等。这个里面有两个方法需要注意,如下:
/*
* 只有在IoSession的read方法可用的时候返回true。 如果可用,受到的消息
* 保存在BlockingQueue这样对那个客户端应用程序来说更方便取到消息。开
* 启这个对服务器没什么好处,并且可能造成内存漏洞,默认是不开启的。
*/
boolean isUseReadOperation();
/*
* 打开或关闭IoSession的read方法。
*/
void setUseReadOperation(boolean useReadOperation);
3、IoSessionInitializer定义了一个回调函数,用于把用户自定义的会话初始化行为剥离出来:
public interface IoSessionInitializer<T extends IoFuture> {
void initializeSession(IoSession session, T future);
}
4、IoSessionRecycler为一个无连接的传输服务提供回收现有会话的服务:
public interface IoSessionRecycler {
/**
* 一个虚假的recycler(并不回收任何session)。但是用这个可以使得所有session
* 的生命周期事件被fired
*/
static IoSessionRecycler NOOP = new IoSessionRecycler() {
public void put(IoSession session) {}
public IoSession recycle(SocketAddress localAddress,SocketAddress remoteAddress) {
return null;
}
public void remove(IoSession session) {}
};
/*
* 创建或写Iossion的时候被调用。
*/
void put(IoSession session);
/*
* 尝试获取一个被回收了的IoSession。
*/
IoSession recycle(SocketAddress localAddress, SocketAddress remoteAddress);
/*
* 会话被关闭的时候调用。
*/
void remove(IoSession session);
}
ExpiringSessionRecycler是IoSessionRecycler的一个实现,用来回收超时失效的会话:
private ExpiringMap<Object, IoSession> sessionMap;//待处理的会话
private ExpiringMap<Object, IoSession>.Expirer mapExpirer;//负责具体的回收工作
下面来看Key是什么样的:
private Object generateKey(SocketAddress localAddress,SocketAddress remoteAddress) {
List<SocketAddress> key = new ArrayList<SocketAddress>(2);
key.add(remoteAddress);
key.add(localAddress);
return key;
}
ExpiringMap中保存了超过限制的对象和该对象的监听器,如下:
public class ExpiringMap<K, V> implements Map<K, V> {
public static final int DEFAULT_TIME_TO_LIVE = 60;
public static final int DEFAULT_EXPIRATION_INTERVAL = 1;
private static volatile int expirerCount = 1;
private final ConcurrentHashMap<K, ExpiringObject> delegate;
private final CopyOnWriteArrayList<ExpirationListener<V>> expirationListeners;
private final Expirer expirer;
}
其中的ExpiringObject表示一个超过限制的对象,是ExpiringMap的一个内部类,如下:
private class ExpiringObject {
private K key;
private V value;
private long lastAccessTime;//上次访问时间
private final ReadWriteLock lastAccessTimeLock = new ReentrantReadWriteLock();
}
mapExpirer用来移除sessionMap上超过临界值的项,关键代码如下:
private void processExpires() {
long timeNow = System.currentTimeMillis();//当前时间
for (ExpiringObject o : delegate.values()) {
if (timeToLiveMillis <= 0) {
continue;
}
long timeIdle = timeNow - o.getLastAccessTime();
if (timeIdle >= timeToLiveMillis) {
delegate.remove(o.getKey());//移除
for (ExpirationListener<V> listener : expirationListeners) {
listener.expired(o.getValue());//终止监听?
}
}
}
}
启动关闭该县城都需要进行封锁机制。
5、Mina中的I/O事件类型如下:
public enum IoEventType {
SESSION_CREATED,
SESSION_OPENED,
SESSION_CLOSED,
MESSAGE_RECEIVED,
MESSAGE_SENT,
SESSION_IDLE,
EXCEPTION_CAUGHT,
WRITE,
CLOSE,
}
IoEvent表示一个I/O事件或者一个I/O请求,包括时间类型、所属会话、时间参数:
public class IoEvent implements Runnable {
private final IoEventType type;
private final IoSession session;
private final Object parameter;
public IoEvent(IoEventType type, IoSession session, Object parameter) {
//...
}
//根据事件类型向会话的过滤链上的众多监听者发出事件到来的信号。
public void fire() {
switch (getType()) {
case MESSAGE_RECEIVED:
getSession().getFilterChain().fireMessageReceived(getParameter());break;
case MESSAGE_SENT:
getSession().getFilterChain().fireMessageSent((WriteRequest) getParameter());break;
case WRITE:
getSession().getFilterChain().fireFilterWrite((WriteRequest) getParameter());break;
case CLOSE:
getSession().getFilterChain().fireFilterClose();break;
case EXCEPTION_CAUGHT:
getSession().getFilterChain().fireExceptionCaught((Throwable) getParameter());break;
case SESSION_IDLE:
getSession().getFilterChain().fireSessionIdle((IdleStatus) getParameter());break;
case SESSION_OPENED:
getSession().getFilterChain().fireSessionOpened();
break;
case SESSION_CREATED:
getSession().getFilterChain().fireSessionCreated();
break;
case SESSION_CLOSED:
getSession().getFilterChain().fireSessionClosed();
break;
default:
throw new IllegalArgumentException("Unknown event type: " + getType());
}
}
public String toString() {
if (getParameter() == null) {
return "[" + getSession() + "] " + getType().name();
}
return "[" + getSession() + "] " + getType().name() + ": "+ getParameter();
}
}
Mina的会话中,有三种类型的闲置状态:READER_IDLE读端空闲、WRITER_IDLE写端空闲、BOTH_IDLE读写都空闲。为了节省会话资源可以让用户设置当空闲超过一定时间后关闭会话,因为此会话可能在一段出现问题,从而导致另一端空闲超过太长时间。
6、DefaultIoSessionDataStructureFactory是IoSessionDataStructureFactory的一个默认的实现:
public class DefaultIoSessionDataStructureFactory implements IoSessionDataStructureFactory {
public IoSessionAttributeMap getAttributeMap(IoSession session) throws Exception {
return new DefaultIoSessionAttributeMap();
}
public WriteRequestQueue getWriteRequestQueue(IoSession session) throws Exception {
return new DefaultWriteRequestQueue();
}
private static class DefaultIoSessionAttributeMap implements IoSessionAttributeMap {
private final Map<Object, Object> attributes = Collections.synchronizedMap(new HashMap<Object, Object>(4));
public DefaultIoSessionAttributeMap() {
super();
}
public Object getAttribute(IoSession session, Object key, Object defaultValue) {
if (key == null) {
throw new NullPointerException("key");
}
Object answer = attributes.get(key);
if (answer == null) {
return defaultValue;
}
return answer;
}
public Object setAttribute(IoSession session, Object key, Object value) {
if (key == null) {
throw new NullPointerException("key");
}
if (value == null) {
return attributes.remove(key);
}
return attributes.put(key, value);
}
public Object setAttributeIfAbsent(IoSession session, Object key, Object value) {
if (key == null) {
throw new NullPointerException("key");
}
if (value == null) {
return null;
}
Object oldValue;
synchronized (attributes) {
oldValue = attributes.get(key);
if (oldValue == null) {
attributes.put(key, value);
}
}
return oldValue;
}
public Object removeAttribute(IoSession session, Object key) {
if (key == null) {
throw new NullPointerException("key");
}
return attributes.remove(key);
}
public boolean removeAttribute(IoSession session, Object key, Object value) {
if (key == null) {
throw new NullPointerException("key");
}
if (value == null) {
return false;
}
synchronized (attributes) {
if (value.equals(attributes.get(key))) {
attributes.remove(key);
return true;
}
}
return false;
}
public boolean replaceAttribute(IoSession session, Object key, Object oldValue, Object newValue) {
synchronized (attributes) {
Object actualOldValue = attributes.get(key);
if (actualOldValue == null) {
return false;
}
if (actualOldValue.equals(oldValue)) {
attributes.put(key, newValue);
return true;
}
return false;
}
}
public boolean containsAttribute(IoSession session, Object key) {
return attributes.containsKey(key);
}
public Set<Object> getAttributeKeys(IoSession session) {
synchronized (attributes) {
return new HashSet<Object>(attributes.keySet());
}
}
public void dispose(IoSession session) throws Exception {}
}
private static class DefaultWriteRequestQueue implements WriteRequestQueue {
//一个队列存储传入的写请求
private final Queue<WriteRequest> q = new CircularQueue<WriteRequest>(16);
public DefaultWriteRequestQueue() {
super();
}
//...
}
}
7、AbstractIoSession是IoSession的一个抽象实现类,如下:
private IoSessionAttributeMap attributes;//会话属性
private WriteRequestQueue writeRequestQueue;//写请求队列
private WriteRequest currentWriteRequest;//当前写请求
下面是关闭的时候涉及的成员:
//要结束当前会话时发送写请求CLOSE_REQUEST
private static final WriteRequest CLOSE_REQUEST =
new DefaultWriteRequest(new Object());
//在连接关闭时状态被设置为closed
private final CloseFuture closeFuture = new DefaultCloseFuture(this);
//关闭的监听器
private static final IoFutureListener<CloseFuture> SCHEDULED_COUNTER_RESETTER =
new IoFutureListener<CloseFuture>() {
public void operationComplete(CloseFuture future) {
AbstractIoSession session = (AbstractIoSession) future.getSession();
session.scheduledWriteBytes.set(0);
session.scheduledWriteMessages.set(0);
session.readBytesThroughput = 0;
session.readMessagesThroughput = 0;
session.writtenBytesThroughput = 0;
session.writtenMessagesThroughput = 0;
}
};
close和closeOnFlush都是异步操作的,区别是前者立即关闭连接,后者是在写请求队列中放入一个CLOSE_REQUEST并将其即时刷新储蓄,若要真正等到关闭完成,需要调用方法在返回的CloseFuture等待。下面是close的代码:
public final CloseFuture close() {
synchronized (lock) {
if (isClosing()) {
return closeFuture;
}
closing = true;
}
getFilterChain().fireFilterClose();//fire出关闭事件
return closeFuture;
}
下面是closeOnFlush的代码:
private final CloseFuture closeOnFlush() {
getWriteRequestQueue().offer(this, CLOSE_REQUEST);
getProcessor().flush(this);
return closeFuture;
}
对于读的情况,下面是取得读的数据队列:
//返回可被读取数据队列
private Queue<ReadFuture> getReadyReadFutures() {
Queue<ReadFuture> readyReadFutures = (Queue<ReadFuture>) getAttribute(READY_READ_FUTURES_KEY);
//如果是第一次读取数据
if (readyReadFutures == null) {
//构造一个新的读数据队列
readyReadFutures = new CircularQueue<ReadFuture>();
Queue<ReadFuture> oldReadyReadFutures = (Queue<ReadFuture>) setAttributeIfAbsent(READY_READ_FUTURES_KEY, readyReadFutures);
if (oldReadyReadFutures != null) {
readyReadFutures = oldReadyReadFutures;
}
}
return readyReadFutures;
}
读数据的过程:
public final ReadFuture read() {
//配置不允许读数据
if (!getConfig().isUseReadOperation()) {
throw new IllegalStateException("useReadOperation is not enabled.");
}
//获得已经被许可的可被读数据队列
Queue<ReadFuture> readyReadFutures = getReadyReadFutures();
ReadFuture future;
synchronized (readyReadFutures) {
future = readyReadFutures.poll();
if (future != null) {
//如果关联的会话已关闭,通知读者
if (future.isClosed()) {
readyReadFutures.offer(future);
}
} else {
future = new DefaultReadFuture(this);
//将数据出入等待读的队列
getWaitingReadFutures().offer(future);
}
}
return future;
}
写数据的过程:
//IoBuffer、文件、文件部分区域
public WriteFuture write(Object message, SocketAddress remoteAddress) {
if (message == null) {
throw new NullPointerException("message");
}
//如果没有远端地址
if (!getTransportMetadata().isConnectionless() && remoteAddress != null) {
throw new UnsupportedOperationException();
}
//如果会话已被关闭
if (isClosing() || !isConnected()) {
WriteFuture future = new DefaultWriteFuture(this);
WriteRequest request = new DefaultWriteRequest(message, future, remoteAddress);
WriteException writeException = new WriteToClosedSessionException(request);
future.setException(writeException);
return future;
}
FileChannel openedFileChannel = null;
try {
if (message instanceof IoBuffer && !((IoBuffer) message).hasRemaining()) {//如果是空消息
throw new IllegalArgumentException("message is empty. Forgot to call flip()?");
} else if (message instanceof FileChannel) {//文件的某一区域
FileChannel fileChannel = (FileChannel) message;
message = new DefaultFileRegion(fileChannel, 0, fileChannel.size());
} else if (message instanceof File) {//要发送的是文件
File file = (File) message;
openedFileChannel = new FileInputStream(file).getChannel();//打开文件通道
message = new DefaultFileRegion(openedFileChannel, 0, openedFileChannel.size());
}
} catch (IOException e) {
ExceptionMonitor.getInstance().exceptionCaught(e);
return DefaultWriteFuture.newNotWrittenFuture(this, e);
}
//构造写请求,通过过滤器链发送出去
WriteFuture writeFuture = new DefaultWriteFuture(this);
WriteRequest writeRequest = new DefaultWriteRequest(message, writeFuture, remoteAddress);
IoFilterChain filterChain = getFilterChain();
filterChain.fireFilterWrite(writeRequest);
//如果打开文件通道应该在完成时关闭通道
if (openedFileChannel != null) {
final FileChannel finalChannel = openedFileChannel;
writeFuture.addListener(new IoFutureListener<WriteFuture>() {
public void operationComplete(WriteFuture future) {
try {
finalChannel.close();
} catch (IOException e) {
ExceptionMonitor.getInstance().exceptionCaught(e);
}
}
});
}
return writeFuture;
}