通过mina官 网文档,我们可以看到,有如下几个状态:
connected : the session has been created and is available
idle : the session hasn’t processed any request for at least a period of time (this period is configurable)closing : the session is being closed (the remaining messages are being flushed, cleaning up is not terminated)
idle for read : no read has actually been made for a period of time
idle for write : no write has actually been made for a period of time
idle for both : no read nor write for a period of time
closed : the session is now closed, nothing else can be done to revive it.
对应的状态迁移图,如图所示:

通过上面的状态图,我们可以看出,是哪个事件的发生使得iosession进入哪个状态,比较直观明了。下面,我们看一下iosession对应的设计,类继承关系如下所示:
对于iosession接口类,我在上图把具有不同类型功能的操作进行了分类,说明如下:
一个iosession实例可以访问/持有哪些数据:前半部分以get开头的方法,能够返回对应的数据对象。
一个iosession实例可以检测哪些状态数据:中间部分以is开头的一些方法。
一个iosession实例可以执行哪些方法调用:后半部分以动词开头命名的方法。
一个iosession实例还可以获取通信过程相关的统计信息,如读取字节数/消息数、写入字节数/消息数,等等,在上面类图中省略 了这些方法。
可见,iosession在mina框架中的位置是相当重要的。
根据上面的类图,我们分析一下niosocketsession类的源代码。
abstractiosession实现了iosession接口中定义的大多数方法,我们关注读和写两个重要的方法,因为他们最终也被niosocketsession类所继承。
先看读数据请求方法read,如下所示:
<code>01</code>
<code>public</code> <code>final</code> <code>readfuture read() {</code>
<code>02</code>
<code></code><code>if</code> <code>(!getconfig().isusereadoperation()) {</code>
<code>03</code>
<code></code><code>throw</code> <code>new</code> <code>illegalstateexception(</code><code>"usereadoperation is not enabled."</code><code>);</code>
<code>04</code>
<code></code><code>}</code>
<code>05</code>
<code>06</code>
<code></code><code>queue<readfuture> readyreadfutures = getreadyreadfutures();</code><code>// 获取到read请求就绪队列</code>
<code>07</code>
<code></code><code>readfuture future;</code>
<code>08</code>
<code></code><code>synchronized</code> <code>(readyreadfutures) {</code><code>// 这个对就绪队列是共享的,对于读请求之间需要进行同步</code>
<code>09</code>
<code></code><code>future = readyreadfutures.poll();</code><code>// 出队</code>
<code>10</code>
<code></code><code>if</code> <code>(future !=</code><code>null</code><code>) {</code><code>// 如果队列中有就绪的read请求</code>
<code>11</code>
<code></code><code>if</code> <code>(future.isclosed()) {</code><code>// 如果与该iosession相关的readfuture已经关闭(读取完成)</code>
<code>12</code>
<code></code><code>readyreadfutures.offer(future);</code><code>// 还要将这个readfuture放入到队列,等待该iosession下次可能的读请求</code>
<code>13</code>
<code>14</code>
<code></code><code>}</code><code>else</code> <code>{</code>
<code>15</code>
<code></code><code>future =</code><code>new</code> <code>defaultreadfuture(</code><code>this</code><code>);</code><code>// 如果是与该iosession相关的第一次读请求,目前读就绪队列肯定没有一个readfuture实例,则需要创建一个</code>
<code>16</code>
<code></code><code>getwaitingreadfutures().offer(future);</code><code>// 将新创建的readfuture实例放入到等待读队列</code>
<code>17</code>
<code>18</code>
<code>19</code>
<code>20</code>
<code></code><code>return</code> <code>future;</code><code>// 返回一个readfuture实例,无论是第一次发出读请求,还是上一次读请求已经完成,对于本次读请求都将返回这个readfuture实例</code>
<code>21</code>
<code>}</code>
再看一下,写数据请求方法write,如下所示:
<code>public</code> <code>writefuture write(object message, socketaddress remoteaddress) {</code>
<code></code><code>if</code> <code>(message ==</code><code>null</code><code>) {</code>
<code></code><code>throw</code> <code>new</code> <code>illegalargumentexception(</code><code>"trying to write a null message : not allowed"</code><code>);</code>
<code></code><code>if</code> <code>(!gettransportmetadata().isconnectionless() && (remoteaddress !=</code><code>null</code><code>)) {</code>
<code></code><code>throw</code> <code>new</code> <code>unsupportedoperationexception();</code>
<code></code><code>if</code> <code>(isclosing() || !isconnected()) {</code><code>// 如果该次会话正在关闭,或者就没有连接过,则封装一个异常返回一个writefuture对象</code>
<code></code><code>writefuture future =</code><code>new</code> <code>defaultwritefuture(</code><code>this</code><code>);</code>
<code></code><code>writerequest request =</code><code>new</code> <code>defaultwriterequest(message, future, remoteaddress);</code>
<code></code><code>writeexception writeexception =</code><code>new</code> <code>writetoclosedsessionexception(request);</code>
<code></code><code>future.setexception(writeexception);</code>
<code></code><code>return</code> <code>future;</code>
<code></code><code>filechannel openedfilechannel =</code><code>null</code><code>;</code>
<code></code><code>try</code> <code>{</code>
<code></code><code>if</code> <code>((message</code><code>instanceof</code> <code>iobuffer) && !((iobuffer) message).hasremaining()) {</code><code>// 没有写任何数据</code>
<code>22</code>
<code></code><code>throw</code> <code>new</code> <code>illegalargumentexception(</code><code>"message is empty. forgot to call flip()?"</code><code>);</code>
<code>23</code>
<code></code><code>}</code><code>else</code> <code>if</code> <code>(message</code><code>instanceof</code> <code>filechannel) {</code>
<code>24</code>
<code></code><code>filechannel filechannel = (filechannel) message;</code>
<code>25</code>
<code></code><code>message =</code><code>new</code> <code>defaultfileregion(filechannel,</code><code>0</code><code>, filechannel.size());</code><code>// 如果是filechannel,则创建一个defaultfileregion对象,用来被mina操纵</code>
<code>26</code>
<code></code><code>}</code><code>else</code> <code>if</code> <code>(message</code><code>instanceof</code> <code>file) {</code>
<code>27</code>
<code></code><code>file file = (file) message;</code>
<code>28</code>
<code></code><code>openedfilechannel =</code><code>new</code> <code>fileinputstream(file).getchannel();</code>
<code>29</code>
<code></code><code>message =</code><code>new</code> <code>filenamefileregion(file, openedfilechannel,</code><code>0</code><code>, openedfilechannel.size());</code><code>// 如果是file,则创建filenamefileregion</code>
<code>30</code>
<code>31</code>
<code></code><code>}</code><code>catch</code> <code>(ioexception e) {</code>
<code>32</code>
<code></code><code>exceptionmonitor.getinstance().exceptioncaught(e);</code>
<code>33</code>
<code></code><code>return</code> <code>defaultwritefuture.newnotwrittenfuture(</code><code>this</code><code>, e);</code>
<code>34</code>
<code>35</code>
<code>36</code>
<code></code><code>// 可以写message了,做写前准备</code>
<code>37</code>
<code></code><code>writefuture writefuture =</code><code>new</code> <code>defaultwritefuture(</code><code>this</code><code>);</code>
<code>38</code>
<code></code><code>writerequest writerequest =</code><code>new</code> <code>defaultwriterequest(message, writefuture, remoteaddress);</code>
<code>39</code>
<code>40</code>
<code></code><code>// then, get the chain and inject the writerequest into it</code>
<code>41</code>
<code></code><code>iofilterchain filterchain = getfilterchain();</code><code>// 获取到与该iosession相关的iofilterchain,方法getfilterchain实现可以看niosocketsession类中的实现:filterchain = new defaultiofilterchain(this);</code>
<code>42</code>
<code></code><code>filterchain.firefilterwrite(writerequest);</code><code>// 触发写事件,将writerequest注入到iofilter实例链,执行注册的iofilter的逻辑</code>
<code>43</code>
<code>44</code>
<code></code><code>// 不关心filechannel的操作,不进行处理,直接关闭掉</code>
<code>45</code>
<code></code><code>if</code> <code>(openedfilechannel !=</code><code>null</code><code>) {</code>
<code>46</code>
<code></code><code>final</code> <code>filechannel finalchannel = openedfilechannel;</code>
<code>47</code>
<code></code><code>writefuture.addlistener(</code><code>new</code> <code>iofuturelistener<writefuture>() {</code>
<code>48</code>
<code></code><code>public</code> <code>void</code> <code>operationcomplete(writefuture future) {</code>
<code>49</code>
<code>50</code>
<code></code><code>finalchannel.close();</code>
<code>51</code>
<code>52</code>
<code>53</code>
<code>54</code>
<code>55</code>
<code></code><code>});</code>
<code>56</code>
<code>57</code>
<code>58</code>
<code></code><code>return</code> <code>writefuture;</code><code>// 返回writefuture,等待写操作异步完成</code>
<code>59</code>
再看,niosession类中增加了一个返回ioprocessor实例的抽象方法,而这个ioprocessor是在创建一个iosession实例(例如,可以实例化一个niosocketsession)的时候,由外部传到iosession内部。我们知道,ioprocessor是mina框架底层真正用来处理实际i/o操作的处理器,通过一个iosession实例获取一个ioprocessor,可以方便地响应作用于iosession的i/o读写请求,从而由这个ioprocessor直接去处理。
根据mina框架架构设计,ioservice->iofilter chain->iohandler,我们知道在iofilter chain的一端(头部)之前会调用处理实际的i/o操作请求,也就是ioprocessor需要处理的逻辑,那么可以想象到,ioprocessor被调用的位置,可以查看org.apache.mina.core.filterchain.defaultiofilterchain类的源代码,其中定义了一个内部类,源码如下所示:
<code>private</code> <code>class</code> <code>headfilter</code><code>extends</code> <code>iofilteradapter {</code>
<code></code><code>@suppresswarnings</code><code>(</code><code>"unchecked"</code><code>)</code>
<code></code><code>@override</code>
<code></code><code>public</code> <code>void</code> <code>filterwrite(nextfilter nextfilter, iosession session, writerequest writerequest)</code><code>throws</code> <code>exception {</code>
<code></code><code>abstractiosession s = (abstractiosession) session;</code>
<code></code><code>// maintain counters.</code>
<code></code><code>if</code> <code>(writerequest.getmessage()</code><code>instanceof</code> <code>iobuffer) {</code>
<code></code><code>iobuffer buffer = (iobuffer) writerequest.getmessage();</code>
<code></code><code>// i/o processor implementation will call buffer.reset()</code>
<code></code><code>// it after the write operation is finished, because</code>
<code></code><code>// the buffer will be specified with messagesent event.</code>
<code></code><code>buffer.mark();</code>
<code></code><code>int</code> <code>remaining = buffer.remaining();</code>
<code></code><code>if</code> <code>(remaining ==</code><code>0</code><code>) {</code>
<code></code><code>// zero-sized buffer means the internal message</code>
<code></code><code>// delimiter.</code>
<code></code><code>s.increasescheduledwritemessages();</code>
<code></code><code>s.increasescheduledwritebytes(remaining);</code>
<code></code><code>writerequestqueue writerequestqueue = s.getwriterequestqueue();</code>
<code></code><code>if</code> <code>(!s.iswritesuspended()) {</code>
<code></code><code>if</code> <code>(writerequestqueue.size() ==</code><code>0</code><code>) {</code>
<code></code><code>// we can write directly the message</code>
<code></code><code>s.getprocessor().write(s, writerequest);</code>
<code></code><code>s.getwriterequestqueue().offer(s, writerequest);</code>
<code></code><code>s.getprocessor().flush(s);</code>
<code></code><code>public</code> <code>void</code> <code>filterclose(nextfilter nextfilter, iosession session)</code><code>throws</code> <code>exception {</code>
<code></code><code>((abstractiosession) session).getprocessor().remove(session);</code>
最后,我们看一下niosocketsession实例被创建的时机。其实很容易想到,当一次网络通信开始的时候,也就是客户端连接到服务器端的时候,服务器端首先进行accept,这时候一次会话才被启动,也就是在这个是被创建,拿mina中的niosocketacceptor类来看,创建niosocketsession的代码,如下所示:
<code>protected</code> <code>niosession accept(ioprocessor<niosession> processor, serversocketchannel handle)</code><code>throws</code> <code>exception {</code>
<code></code><code>selectionkey key = handle.keyfor(selector);</code>
<code></code><code>if</code> <code>((key ==</code><code>null</code><code>) || (!key.isvalid()) || (!key.isacceptable())) {</code>
<code></code><code>return</code> <code>null</code><code>;</code>
<code></code><code>// accept the connection from the client</code>
<code></code><code>socketchannel ch = handle.accept();</code>
<code></code><code>if</code> <code>(ch ==</code><code>null</code><code>) {</code>
<code></code><code>return</code> <code>new</code> <code>niosocketsession(</code><code>this</code><code>, processor, ch);</code><code>// 创建niosocketsession实例</code>
通过上面的分析,我们可知,iosession在基于mina进行网络通信的过程中,对于网络通信相关操作的请求都是基于一个iosession实例来进行的,所以说,iosession在mina中是一个很重要的结构。