简介

session类图

Mina每建立一个连接同时会创建一个session对象,用于保存这次读写需要用到的所有信息。从抽象类AbstractIoSession中可以看出session具有如下功能:
1、从attributes成员可以看出session可以存放用户关心的键值对
2、注意到WriteRequestQueue,这是一个写请求队列,processor中调用flush或者flushNow方法时会将用户写入的数据包装成一个writeRequest对象,并加入这个队列中。
3、提供了大量的统计功能,比如接收到了多少消息、最后读取时间等
在代码中一般是这样使用session的
// 创建服务器监听
IoAcceptor acceptor = new NioSocketAcceptor();
// 设置buffer的长度
acceptor.getSessionConfig().setReadBufferSize(2048);
// 设置连接超时时间
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);

session做为一个连接的具体对象,缓存当前连接用户的一些信息。

创建好acceptor或者connector之后,通过IoSessionConfig对session对行配置。
用得最多的是通过session写入数据,这是调用了IoSession的write方法
WriteFuture write(Object message);
WriteFuture write(Object message, SocketAddress destination);

下面着重分析创建过程以及session的状态

创建与初始化

每建立一个连接,就会创建一个session,IoAcceptor的accept方法的返回值正是一个session。见NioSocketAcceptor.accept(IoProcessor<NioSession> processor, ServerSocketChannel handle)方法:

 protected NioSession accept(IoProcessor<NioSession> processor, ServerSocketChannel handle) throws Exception {

        SelectionKey key = handle.keyFor(selector);

        if ((key == null) || (!key.isValid()) || (!key.isAcceptable())) {
return null;
} // accept the connection from the client
SocketChannel ch = handle.accept(); if (ch == null) {
return null;
} return new NioSocketSession(this, processor, ch);
}
由以上代码可知,session包含了对众多对象的引用,比如processor,socketChannel,SelectionKey,IoFilter等。
session在创建好后,紧接着就会对其进行初始化。AbstractIoService.initSession(IoSession session, IoFuture future, IoSessionInitializer sessionInitializer)方法如下:

    protected final void initSession(IoSession session, IoFuture future, IoSessionInitializer sessionInitializer) {
// Update lastIoTime if needed.
if (stats.getLastReadTime() == 0) {
stats.setLastReadTime(getActivationTime());
} if (stats.getLastWriteTime() == 0) {
stats.setLastWriteTime(getActivationTime());
} // Every property but attributeMap should be set now.
// Now initialize the attributeMap. The reason why we initialize
// the attributeMap at last is to make sure all session properties
// such as remoteAddress are provided to IoSessionDataStructureFactory.
try {
((AbstractIoSession) session).setAttributeMap(session.getService().getSessionDataStructureFactory()
.getAttributeMap(session));
} catch (IoSessionInitializationException e) {
throw e;
} catch (Exception e) {
throw new IoSessionInitializationException("Failed to initialize an attributeMap.", e);
} try {
((AbstractIoSession) session).setWriteRequestQueue(session.getService().getSessionDataStructureFactory()
.getWriteRequestQueue(session));
} catch (IoSessionInitializationException e) {
throw e;
} catch (Exception e) {
throw new IoSessionInitializationException("Failed to initialize a writeRequestQueue.", e);
} if ((future != null) && (future instanceof ConnectFuture)) {
// DefaultIoFilterChain will notify the future. (We support ConnectFuture only for now).
session.setAttribute(DefaultIoFilterChain.SESSION_CREATED_FUTURE, future);
} if (sessionInitializer != null) {
sessionInitializer.initializeSession(session, future);
} finishSessionInitialization0(session, future);
}
设置上次读写时间,初始化属性map和写请求队列等。
session被初始化好之后会加入到processor中,processor中有一个队列专门存放session:
例如:AbstractPollingIoProcessor.java中有:

private final Queue<S> newSessions = new ConcurrentLinkedQueue<S>();

    /** A queue used to store the sessions to be removed */
private final Queue<S> removingSessions = new ConcurrentLinkedQueue<S>(); /** A queue used to store the sessions to be flushed */
private final Queue<S> flushingSessions = new ConcurrentLinkedQueue<S>(); /**
* A queue used to store the sessions which have a trafficControl to be
* updated
*/
private final Queue<S> trafficControllingSessions = new ConcurrentLinkedQueue<S>(); /** The processor thread : it handles the incoming messages */
private final AtomicReference<Processor> processorRef = new AtomicReference<Processor>();
加入队列之后,processor就会从队列中取出session,以下是processor的run方法关键代码:
  1. private class Processor implements Runnable {
    public void run() {
    for (;;) {
    long t0 = System.currentTimeMillis();
    int selected = select(SELECT_TIMEOUT);
    long t1 = System.currentTimeMillis();
    long delta = (t1 - t0); if ((selected == 0) && !wakeupCalled.get() && (delta < 100)) {
    if (isBrokenConnection()) {
    wakeupCalled.getAndSet(false);
    continue;
    } else {
    registerNewSelector();
    }
    wakeupCalled.getAndSet(false);
    continue;
    } nSessions += handleNewSessions(); updateTrafficMask(); if (selected > 0) {
    process();
    } nSessions -= removeSessions(); }
    }
    }

1、不断地调用select方法来检查是否有session准备就绪,如果没有或者间隔时间小于100ms则检查selector是否可用,如果不可用重新建一个selector(这里linux下的epoll的问题可能导致selector不可用。)

2、从newSessions队列中取出这些session,并将其负责的通道注册到selector上
3、处理准备就绪的session
AbstractPollingIoProcessor.java

private void process(S session) {
// Process Reads
if (isReadable(session) && !session.isReadSuspended()) {
read(session);
} // Process writes
if (isWritable(session) && !session.isWriteSuspended()) {
// add the session to the queue, if it's not already there
if (session.setScheduledForFlush(true)) {
flushingSessions.add(session);
}
}
}
总结一下创建与初始化过程:连接到来创建一个session,初始化好之后加入到processor负责的一个队列中。processor线程会把队列中的session对应的通道都注册到它自己的selector上,然后这个selector轮询这些通道是否准备就绪,一旦准备就绪就调用对应方法进行处理(read or flushNow)。

状态

Mina中的session具有状态,且状态之间是可以相互转化的
Connected:session被创建时处于这种状态
Idle:没有请求可以处理(可配置)
Closing:正处于关闭状态(可能正在做一些清理工作)
Closed:关闭状态
下图是这几种状态之间的转化图:

IoFilter与IoHandler就是在这些状态上面加以干预,下面重点看一下IDLE状态,它分三种:

Idle for read:在规定时间内没有数据可读
Idle for write:在规定时间内没有数据可写
Idle for both:在规定时间内没有数据可读和可写
这三种状态分别对应IdleStatus类的三个常量:READER_IDLE、WRITER_IDLE、BOTH_IDLE
前面session的用法中有如下设置:

acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10); 
acceptor的run方法中调用了notifyIdleSessions

每隔一秒一检查是否到达了设置的空闲时间

  1. private static void notifyIdleSession0(IoSession session, long currentTime, long idleTime, IdleStatus status,
    long lastIoTime) {
    if ((idleTime > 0) && (lastIoTime != 0) && (currentTime - lastIoTime >= idleTime)) {
    session.getFilterChain().fireSessionIdle(status);
    }
    }

如果当前时间减去上一次IDLE事件触发的时间大于用户设置的idleTime,则触发一次sessionIdle事件。

public void fireSessionIdle(IdleStatus status) {
session.increaseIdleCount(status, System.currentTimeMillis());
Entry head = this.head;
callNextSessionIdle(head, session, status);
}

increaseIdleCount这个方法会更新lastToTime的值为当前时间,紧接着穿透过滤器链(当然在过滤器的sessionIdle中可能会做一些操作)到达IoHandler的sessionIdle方法,如果需要在session空闲的时候做一些操作,就可以在这个方法里面做。

 
 

mina2中的session的更多相关文章

  1. 在 ASP.NET CORE 中使用 SESSION

    Session 是保存用户和 Web 应用的会话状态的一种方法,ASP.NET Core 提供了一个用于管理会话状态的中间件.在本文中我将会简单介绍一下 ASP.NET Core 中的 Session ...

  2. Tomcat中的Session小结

    什么是Session 对Tomcat而言,Session是一块在服务器开辟的内存空间,其存储结构为ConcurrentHashMap: Session的目的 Http协议是一种无状态协议,即每次服务端 ...

  3. .ashx中使用Session

    在一般处理程序中给session赋值是报错:未将对象引用设置到对象的实例.

  4. strust2中使用session

    在Struts2里,如果需要在Action中使用session,可以通过下面两种方式得到1.通过ActionContext class中的方法getSession得到2.Action实现org.apa ...

  5. 在IHttpHandler中获取session

    因为业务要异步通过IHttpHandler获得数据,但还要根据当前登录人员的session过滤,因此要在在IHttpHandler中获取session 方法是HttpHandler容器中如果需要访问S ...

  6. Java中对session的简单操作

    1.jsp中操作session <% String name=(String)request.getSession().getAttribute("username"); / ...

  7. ASP.NET中的Session怎么正确使用

    Session对象用于存储从一个用户开始访问某个特定的aspx的页面起,到用户离开为止,特定的用户会话所需要的信息.用户在应用程序的页面切换时,Session对象的变量不会被清除. 对于一个Web应用 ...

  8. 如何在报表权限中使用session

    1. 问题描述 权限中使用session,一般是用来存放用户名和密码,下面以报表开发工具FineReport为例,分两种情况介绍用户名和密码的保存: 2. 同一应用下session 由于session ...

  9. [转]tomcat中的session管理

    转载地址:http://blog.csdn.net/iloveqing/article/details/1544958 当一个sesson开始时,Servlet容器会创建一个HttpSession对象 ...

随机推荐

  1. java第一节感受

    第一节java课考试,感觉自从小学期和实习过了以后就等这个测试了,测试过了以后就是中秋节了,下周再上一节java又放国庆节了. 当时报软工的时候就早早地做好了心理准备,但是当亲身经历一遍后真的有了一种 ...

  2. 《DSP using MATLAB》Problem 6.23

    代码: %% ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ %% Output In ...

  3. 新一代构建工具gradle学习

    简介:Gradle的出现,是技术发展的必然,站在了Ant.maven等构建工具的肩膀上,使用了一种强大且具有表达性的基于Groovy的领域特定语言(DSL),使其拥有易用且灵活的方式去实现定制逻辑.方 ...

  4. day39机器学习

    2 Numpy快速上手 2.1. 什么是Numpy Numpy是Python的一个科学计算的库 主要提供矩阵运算的功能,而矩阵运算在机器学习领域应用非常广泛 Numpy一般与Scipy.matplot ...

  5. 利用 httpmodule 强制所有页面使用同一基类

    public class OMSPageChecker : IHttpModule { public void Dispose() { } public void Init(HttpApplicati ...

  6. 数据库连接池——Druid

    使用步骤: 1.导包,durid1.0.9 jar包 2.定义配置文件,properties文件,名字任意位置也任意, 3.加载文件 4.获得数据库连接池对象  通过DuridDataSourceFa ...

  7. 初等数论及其应用 (第6版) (Kenneth H.Rosen 著)

    第1章 整数 1.1 数和序列 1.2 和与积 1.3 数学归纳法 1.4 斐波那契数 1.5 整除性 第2章 整数的表示法和运算 2.1 整数的表示法 2.2 整数的计算机运算 2.3 整数运算的复 ...

  8. 目前支持WebGL的浏览器有哪些?

    Google Chrome 9+ Mozilla Firefox 4+ Safari 5.1+(仅限于Mac OS X操作系统,不包括Windows) Opera 12 alpha及以上版本 IE9+ ...

  9. APP前端易用性和UI测试

    移动APP使用场景的特点 1.屏幕小: 与Web系统相比,APP安装在手机端,展示屏幕只有几英寸,能够展示的信息就显得非常有限和珍贵,我们需要将有价值的信息放大,放在显眼的位置. 2.场景复杂化: 由 ...

  10. oracle 之 CLUSTER_INTERCONNECTS is not set to the recommended value

    问题:Database parameter CLUSTER_INTERCONNECTS is not set to the recommended value 在Oracle实际应用程序集群环境中可以 ...