1. 程式人生 > >Mina文件 04- 會話

Mina文件 04- 會話

介紹

會話是MINA的核心:每次客戶端連線到伺服器時,都會在伺服器上建立一個新會話,並將保留在記憶體中,直到客戶端斷開連線。如果您在客戶端使用MINA,則每次連線到伺服器時,也會在客戶端上建立會話。

會話是MINA的核心:每次客戶端連線到伺服器時,都會在伺服器上建立一個新會話,並將保留在記憶體中,直到客戶端斷開連線。如果您在客戶端使用MINA,則每次連線到伺服器時,也會在客戶端上建立會話。

這也是您在會話中需要執行的任何操作的訪問點:傳送訊息,關閉會話等...

至關重要的是要理解由於NIO的非同步本質,從會話中讀取並沒有多大意義。實際上,當一些傳入訊息到達時,您的應用程式會發出訊號,這是IoHandler負責處理此類事件。換句話說,不要呼叫session.read()。決不。

會話狀態

會話具有狀態,該狀態將在時間內發展。

1.已連線:會話已建立且可用

2.空閒:會話至少在一段時間內沒有處理任何請求(此時間段是可配置的)

    (1)空閒讀:實際上沒有讀過一段時間

    (2)閒置寫:實際上沒有寫過一段時間

    (3)兩者都空閒:一段時間內沒有讀或寫

3. 關閉中:會話正在關閉(剩餘的訊息正在重新整理,清理不會終止)

4. 已關閉:會話現已關閉,無法通過其他方式恢復會話。這實際上不是一個真實的狀態:當會話關閉時,它被刪除。

以下狀態圖公開了所有可能的狀態和轉換:

 

 

我們有一組方法來獲取有關會話狀態的一些資訊。

會話狀態:

1.isActive():告訴會話是否有效(根據實現可能意味著不同的事情)

2.isClosing():告訴會話是否已被關閉

3.isConnected():告訴會話是否處於活動狀態(即,不處於關閉模式)

 

開啟一個會話

實際上,你無需做任何事情:它是自動的!每當遠端對等方連線到伺服器時,伺服器將建立新連線。在客戶端,每次連線到伺服器時,都會建立一個會話。

此會話作為引數傳遞給您的處理程式,以便您可以在應用程式中對其執行某些操作。在客戶端,當您連線到伺服器時,您可以通過以下方式返回建立的會話:

ConnectFuture connectionFuture = connector.connect(address);
connectionFuture.awaitUninterruptibly();
if (!connectionFuture.isConnected()) { return false; } session = connectionFuture.getSession();

  

您也可以以最短的方式完成:

session = connector.connect(address).getSession();

初始化

建立新會話時,必須對其進行初始化。這是使用預設的IoService配置完成的,您可以稍後更新此配置。實際上,在建立會話時,我們會在內部建立儲存在會話中的預設IoService配置的副本,這是將使用的配置例項(可以修改)。

此初始化還將啟動統計計數器,建立屬性容器,將寫入佇列關聯到會話(這是訊息將被髮送到其中的位置),最終,您是否提供了要執行的特定任務在這個階段,它會呼叫它。

 

關閉會話

會話可以以4種方式關閉,其中兩種是顯式的:當遠端對等方在發生異常時很好地關閉連線時,呼叫closeNow()方法(顯式)呼叫closeOnFlush()方法(顯式)

(注意,不應再使用兩種不推薦使用的方法:close(boolean)和close())

顯式關閉

前兩個方法可以在應用程式的任何地方呼叫,最大的區別是一個(closeNow())將簡單地關閉會話,丟棄任何等待傳輸給對等方的訊息,而closeOnFlush()將等待任何待處理的訊息已傳輸給同伴。

請注意,如果遠端對等體不再連線,則使用_closeOnFlush()_呼叫關閉的會話將永遠不會被銷燬,除非您還處理其空閒狀態,或者在系統TCP超時關閉套接字之前 - 可能需要幾個小時 - 。始終管理應用程式中的空閒狀態。

遠端對等關閉

當遠端對等方正確關閉會話時,將關閉會話,並且將丟棄所有待處理的訊息。這通常是它的工作方式。

但是,有時候,遠端對等方沒有正確關閉連線(這可能發生在電纜被粗暴地拔掉時)。在這種情況下,會話永遠不會被告知斷開連線。瞭解它的唯一方法是定期檢查會話狀態:如果它的空閒時間超過特定時間 - 必須配置 - ,然後應用程式可以決定關閉會話。否則,當達到TCP超時時,會話將最終關閉(可能需要數小時......)。

異常

    在某些情況下,會發生導致會話關閉的例外情況。通常,在建立會話時,我們可能會遇到問題,會話將立即關閉。另一種可能性是我們不能寫一些訊息,例如因為頻道已經關閉:我們然後關閉會話。

總而言之,每當我們在處理會話時遇到異常時,此會話將被關閉。

當然,您的應用程式將通過ExeptionCaught事件通知。

配置

可以為特定會話設定許多不同的引數:

  1.接收緩衝區大小

  2.傳送緩衝區大小

  3.空閒時間

  4.寫資料的超時時間

  5. ……

加上其他配置,具體取決於使用的傳輸型別(參見第6章 – 傳輸)。

所有這些配置引數都儲存在IoSessionConfig物件中,該物件可以使用session.getConfig()方法從會話中獲取。

有關會話配置的更多資訊,請參閱第4.1章 - 會話配置

管理使用者定義的屬性

可能需要儲存一些可能在以後使用的資料。這是使用與每個會話相關聯的專用資料結構來完成的。這是一個鍵值關聯,可以儲存開發人員可能希望在會話期間保持剩餘的任何型別的資料。

例如,如果要跟蹤使用者自建立會話以來發送的請求數,則可以輕鬆將其儲存到此對映中:只需建立與此值關聯的金鑰即可。

int counterValue = session.getAttribute( "counter" );
session.setAttribute( "counter", counterValue + 1 );
...

我們有辦法將儲存的屬性處理到會話中:屬性是鍵/值對,可以從會話的容器中新增,刪除和讀取。

建立會話時會自動建立此容器,並在會話終止時將其銷燬。

會話容器

正如我們所說,這個容器是一個鍵/值容器,預設為Map,但如果想要處理長壽命資料,或者如果它們很大則避免將所有這些資料儲存在記憶體中,也可以定義另一個數據結構。 :我們可以實現一個介面和一個工廠,用於在建立會話時建立此容器。

這段程式碼顯示了在會話初始化期間如何建立容器:

protected final void initSession(IoSession session,
          IoFuture future, IoSessionInitializer sessionInitializer) {
      ...
      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);
      }

如果我們想要定義另一種容器,這裡是我們可以實現的工廠介面:

public interface IoSessionDataStructureFactory {
  /**
  * Returns an {@link IoSessionAttributeMap} which is going to be associated
  * with the specified <tt>session</tt>.  Please note that the returned
  * implementation must be thread-safe.
  */
  IoSessionAttributeMap getAttributeMap(IoSession session) throws Exception;
}

會話屬性訪問

有許多方法可用於操作會話的屬性:

    boolean containsAttribute(Object key):告訴是否存在給定的屬性

    Object getAttribute(Object key):獲取給定屬性的值

    Object getAttribute(Object key,Object defaultValue):獲取給定屬性的值,如果不存在則獲取預設值

    Set <Object> getAttributeKeys():獲取所有儲存屬性的集合

    Object removeAttribute(Object key):刪除給定的屬性

    boolean removeAttribute(Object key,Object value):刪除給定的屬性/值對

    boolean replaceAttribute(Object key,Object oldValue,Object newValue):替換給定屬性/值對

    Object setAttribute(Object key):新增沒有值的新屬性

    Object setAttribute(Object key,Object value):新增新的屬性/值對

    Object setAttributeIfAbsent(Object key):新增一個沒有值的新屬性(如果它尚不存在)

    Object setAttributeIfAbsent(Object key,Object value):新增一個新的屬性/值對,如果它尚不存在

所有這些方法都允許您的應用程式儲存,刪除,獲取或更新儲存在會話中的屬性。另請注意,MINA內部使用了一些屬性:不要輕易修改那些你沒有建立的屬性!

過濾鏈

每個會話都與一系列過濾器相關聯,這些過濾器將在接收或發出傳入請求或傳出訊息時進行處理。這些過濾器是針對每個會話單獨指定的,即使大多數情況下,我們將對所有現有會話使用完全相同的過濾器鏈。

但是,可以動態修改單個會話的鏈,例如通過在鏈中為特定會話新增記錄器篩選器。

統計

每個會話還會記錄會話的內容:

  1.接收/傳送的位元組數

  2.收到/傳送的訊息數量

  3.空閒狀態

  4.吞吐量

和許多其他有用的資訊。

有關會話統計資訊的更多資訊,請參閱第4.2章 - 會話統計資訊

處理器Handler

最後,並非最不重要的是,會話附加到Handler,負責將訊息分發給您的應用程式。此處理程式還將通過使用會話傳送迴響應,只需呼叫write()方法:

  session.write( <your message> );

  

 

第4.1章 - 會話配置

介紹

根據會話的型別,我們可以配置各種元素。其中一些元素在所有會話型別中共享,其他一些是特定的。

我們目前支援4種會話風格:

  1.套接字:支援TCP傳輸

  2.資料報:支援UDP傳輸

  3.Serial:支援RS232傳輸

  4.VmPipe:支援IPC傳輸

一般引數

以下是所有全域性引數的列表(可以為任何會話風格設定它們):

引數

型別

描述

預設值

idleTimeForBoth

int

通知在讀取和寫入時空閒的會話之前等待的秒數

無窮

idleTimeForRead

int

通知讀取空閒的會話之前等待的秒數

無窮

idleTimeForWrite

int

通知寫入時空閒的會話之前等待的秒數

無窮

maxReadBufferSize

int

用於讀取資料的緩衝區的最大大小

65536 bytes

minReadBufferSize

int

用於讀取資料的緩衝區的最小大小

64 bytes

readBufferSize

int

用於讀取incomming資料的緩衝區的預設大小

2048 bytes

throughputCalculationInterval

int

每個吞吐量計算之間的間隔(秒)。

3s

useReadOperation

boolean

當我們允許應用程式執行__session.read()_時,標誌設定為TRUE

FALSE

writeTimeout

int

在挽救寫入操作之前延遲等待完成

60s

可以通過使用getter和setter來訪問所有這些引數(useReadOperation引數getter使用isUseReadOperation()方法)。

 

套接字特定引數

引數

型別

描述

預設值

defaultReuseAddress

boolean

SO_REUSEADDR標誌的值

true

keepAlive

boolean

SO_KEEPALIVE標誌的值

false

oobInline

boolean

SO_OOBINLINE標誌的值

false

receiveBufferSize

int

SO_RCVBUF引數的值

-1

reuseAddress

boolean

SO_REUSEADDR標誌的值

false

sendBufferSize

int

SO_SNDBUF引數的值

-1

soLinger

int

SO_LINGER引數的值

-1

tcpNoDelay

boolean

TCP_NODELAY標誌的值

false

trafficClass

int

IP_TOS引數的值。 IPTOS_LOWCOST(0x02),IPTOS_RELIABILITY(0x04),IPTOS_THROUGHPUT(0x08)或IPTOS_LOWDELAY(0x10)之一

0

 

資料報特定引數

引數

型別

描述

預設值

broadcast

boolean

SO_BROADCAST標誌的值

false

 

closeOnPortUnreachable

boolean

告訴我們是否應該在埠無法訪問時關閉會話

true

 

receiveBufferSize

int

SO_RCVBUF引數的值

-1

 

reuseAddress

boolean

SO_REUSEADDR標誌的值

false

 

sendBufferSize

int

SO_SNDBUF引數的值

-1

 

trafficClass

int

IP_TOS引數的值。 IPTOS_LOWCOST(0x02),IPTOS_RELIABILITY(0x04),IPTOS_THROUGHPUT(0x08)或IPTOS_LOWDELAY(0x10)之一

0

 

序列特定引數

引數

型別

描述

預設值

inputBufferSize

int

要使用的輸入緩衝區大小

8

lowLatency

boolean

設定低延遲模式

false

outputBufferSize

int

要使用的輸出緩衝區大小

8

receiveThreshold

int

以位元組為單位設定接收閾值(將其設定為-1表示禁用)

-1

 

第4.2章 - 會話統計

我們會在每個會話中保留一些有關正在發生的事情的統計資料。並非所有這些統計資料都是通過每條訊息計算出來的:其中一些是按需計算的。

引數

型別

描述

預設值

readBytes

long

自會話建立以來讀取的總位元組數

yes

readBytesThroughput

double

最後一個時間間隔內每秒讀取的位元組數

no

readMessages

long

自會話建立以來讀取的訊息總數

yes

readMessagesThroughput

double

上一個時間間隔內每秒讀取的訊息數

no

scheduledWriteBytes

AtomicInteger

等待寫入的位元組數

yes

scheduledWriteMessages

AtomicInteger

等待寫入的訊息數

yes

writtenBytes

long

自會話建立以來寫入的總位元組數

yes

writtenBytesThroughput

double

最後一個時間間隔內每秒寫入的位元組數

no

writtenMessages

long

自會話建立以來寫入的訊息總數

yes

writtenMessagesThroughput

double

在最後一個時間間隔內每秒寫入的訊息數

no

 

可以使用getter讀取所有這些引數。