前面幾篇介紹完了org.apache.mina.core.service這個包,現在進入org.apache.mina.core.session,這個包主要是圍繞IoSession展開的,包括會話的方方面面。
IoSession接口與底層的傳輸層類型無關(也就是不管是TCP還是UDP),它表示通信雙端的連接。它提供用戶自定義屬性,可以用於在過濾器和處理器之間交換用戶自定義協議相關的信息。
每個會話都有一個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;
}
IoSessionConfig接口用於表示會話的配置信息,主要包括:讀緩衝區大小,會話數據吞吐量,計算吞吐量時間間隔,指定會話端的空閒時間,寫請求操作超時時間。在這個接口中有一個方法值得注意
void setUseReadOperation(boolean useReadOperation);
通過它來設置IoSession的read方法是否啓用,若啓用的話,則所有接收到的消息都會存儲在內部的一個阻塞隊列中,好處在於可以更方便用戶對信息的處理,但對於某些應用來說並不管用,而且還會造成內存泄露,因此默認情況下這個選項是不開啓的。
IoSessionInitializer接口定義了一個回調函數,這在AbstractIoService這個類中的finishSessionInitialization方法中已經見識過它的使用了,用於把用戶自定義的會話初始化行爲剝離出來。
public interface IoSessionInitializer<T extends IoFuture>
{
void initializeSession(IoSession session, T future);
}
IoSessionRecycler接口爲一個無連接的傳輸服務提供回收現有會話的服務,主要的方法是:
IoSession recycle(SocketAddress localAddress, SocketAddress remoteAddress);
一個會話的讀寫能力控制通過TrafficMask類來描述,主要是SelectionKey.OP_READ和SelectionKey.OP_WRITE結合。此類使用單例模式實現,還提供了與,或,非,異或等位操作來動態控制會話讀寫能力。
Mina中的I/O事件類型如下:
public enum IoEventType {
SESSION_CREATED,//會話創建
SESSION_OPENED,//會話打開
SESSION_CLOSED,//會話關閉
MESSAGE_RECEIVED,//接收到消息
MESSAGE_SENT,//發送消息
SESSION_IDLE,//空閒
EXCEPTION_CAUGHT,//異常捕獲
WRITE,
CLOSE,
SET_TRAFFIC_MASK,//設置讀寫能力
}
IoEvent類實現了Runnable接口,表示一個I/O事件或一個I/O請求,包括事件類型,所屬的會話,事件參數值。最重要的方法就是fire,根據事件類型向會話的過濾器鏈上的衆多監聽者發出事件到來的信號。
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 SET_TRAFFIC_MASK:
getSession().getFilterChain().fireFilterSetTrafficMask((TrafficMask) 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());
}
}
Mina的會話中,有三種類型的閒置狀態:
1)READER_IDLE,這表示從遠端沒有數據到來,讀端空閒。
2)WRITER_IDLE,這表示寫端沒有在寫數據。
3)BOTH_IDLE,讀端和寫端都空閒。爲了節約會話資源,可以讓用戶設置當空閒超過一定時間後關閉此會話,因爲此會話可能在某一端出問題了,從而導致另一端空閒超過太長時間。這可以通過使用IoSessionConfig.setIdleTime(IdleStatus,int)來完成,空閒時間閥值在會話配(IoSessionConfig)中設置。
前面介紹過IoSessionDataStructureFactor接口爲會話提供所需要的數據結構,DefaultIoSessionDataStructureFactory是其一個默認實現類。它提供的寫請求隊列內部是一個初始大小爲16的循環隊列,並且在插入隊列尾部和從隊列頭部取數據時都必須滿足互斥同步。
private static class DefaultWriteRequestQueue implements WriteRequestQueue {
private final Queue<WriteRequest> q = new CircularQueue<WriteRequest>(16);
public void dispose(IoSession session) {
}
public void clear(IoSession session) {
q.clear();
}
public synchronized boolean isEmpty(IoSession session) {
return q.isEmpty();
}
public synchronized void offer(IoSession session, WriteRequest writeRequest) {
q.offer(writeRequest);
}
public synchronized WriteRequest poll(IoSession session) {
return q.poll();
}
}