MINA之心跳協議運用
摘要 心跳協議,對基於CS模式的系統開發來說是一種比較常見與有效的連接檢測方式,最近在用MINA框架,原本自己寫了一個心跳協議實現,後來突然發現MINA本身帶有這樣一個心跳實現,感於對框架的小小崇拜,在實踐的同時研究了一下!
MINA本身提供了一個過濾器類: org.apache.mina.filter.keepalive . KeepAliveFilter ,該過濾器用於在IO空閒的時候發送並且反饋心跳包(keep-alive
request/response)。
說到KeepAliveFilter這個類有必要先說一說其構造函數,即實例化該類需要些什麼,該類構造函數中參數有三個分別是:
(1)KeepAvlieMessageFactory: 該實例引用用於判斷接受與發送的包是否是心跳包,以及心跳請求包的實現
(2)IdleStatus: 該過濾器所關注的空閒狀態,默認認爲讀取空閒。 即當讀取通道空閒的時候發送心跳包
(3)KeepAliveRequestTimeoutHandler: 心跳包請求後超時無反饋情況下的處理機制 默認爲CLOSE 即關閉連接
首先需要實現接口 KeepAliveMessageFactory 。 該接口中的抽象方法有:
一般來說心跳機制主要分爲以下四類:
1, active 活躍型: 當讀取通道空閒的時候發送心跳請求,一旦該心跳請求被髮送,那麼需要在keepAliveRequestTimeout時間內接收到心跳反饋,否則KeepAliveRequestTimeoutHandler將會被調用,當一個心跳請求包被接受到後,那麼心跳反饋也會立即發出。
針對活躍型心跳機制: KeepAliveMessageFactory 類的實現方法中: getRequest ( IoSession session)與getResponse ( IoSession session, Object request)必須返回非空。
2, semi-active 半活躍型:當讀取通道空閒的時候發送心跳請求,然而並不在乎心跳反饋有沒有,當一個心跳請求包被接收到後,那麼心跳反饋也會立即發出。
針對半活躍型心跳機制: KeepAliveMessageFactory 類的實現方法中: getRequest ( IoSession session)與getResponse ( IoSession session, Object request)必須返回非空。並且心跳包請求後超時無反饋的處理機制設置爲KeepAliveRequestTimeoutHandler.NOOP(不做任何處理), KeepAliveRequestTimeoutHandler.LOG(只輸出警告信息不做其他處理)
3, passive 被動型:當前IO不希望主動發送心跳請求,但是當接受到一個心跳請求後,那麼該心跳反饋也會立即發出。
針對被動型心跳機制: KeepAliveMessageFactory 類的實現方法中: getRequest ( IoSession session)必須反饋null 與 getResponse ( IoSession session, Object request)必須反饋non-null.
4, deaf speaker 聾子型: 當前IO會主動發送心跳請求,但是不想發送任何心跳反饋。
針對聾子型心跳機制: KeepAliveMessageFactory 類的實現方法中: getRequest ( IoSession session)必須反饋non-null與 getResponse ( IoSession session, Object request)必須反饋null,將KeepAliveRequestTimeoutHandler 設置爲DEAF_SPEAKER.
5, sient-listener 持續監聽型:既不想發送心跳請求也不想發送心跳反饋。
針對持續監聽型心跳機制: KeepAliveMessageFactory 類的實現方法中: getRequest ( IoSession session)必須反饋null 與 getResponse ( IoSession session, Object request)必須反饋null.
心跳包請求超時後的處理機制:接口 KeepAliveRequestTimeoutHandler ,一般該處理主要是針對能夠發送心跳請求的心跳機制。
1.CLOSE:關閉連接
2,LOG:輸出 警告信息
3,NOOP:不做任何處理
4,EXCEPTION:拋出異常
5,DEAF_SPEAKER:一個特殊的處理,停止當前過濾器對對心跳反饋監聽,因此讓過濾器丟失請求超時的偵測功能。(讓其變成聾子)
6,keepAliveRequestTimeout(KeepAliveFilter filter, IoSession session); 自定義處理
下面對客戶端與服務端和分別舉個例子:
服務器:
以被動型心跳機制爲例,服務器在接受到客戶端連接以後被動接受心跳請求,當在規定時間內沒有收到客戶端心跳請求時 將客戶端連接關閉
主要代碼如下:
說到KeepAliveFilter這個類有必要先說一說其構造函數,即實例化該類需要些什麼,該類構造函數中參數有三個分別是:
(1)KeepAvlieMessageFactory: 該實例引用用於判斷接受與發送的包是否是心跳包,以及心跳請求包的實現
(2)IdleStatus: 該過濾器所關注的空閒狀態,默認認爲讀取空閒。 即當讀取通道空閒的時候發送心跳包
(3)KeepAliveRequestTimeoutHandler: 心跳包請求後超時無反饋情況下的處理機制 默認爲CLOSE 即關閉連接
首先需要實現接口 KeepAliveMessageFactory 。 該接口中的抽象方法有:
Modifier and Type | Method and Description |
---|---|
Object |
getRequest(IoSession session)
Returns a (new) keep-alive request message.
|
Object |
getResponse(IoSession session, Object request)
Returns a (new) response message for the specified keep-alive request.
|
boolean |
isRequest(IoSession session, Object message)
Returns true if and only if the specified message is a keep-alive request message.
|
boolean |
isResponse(IoSession session, Object message)
Returns true if and only if the specified message is a keep-alive response message;
|
一般來說心跳機制主要分爲以下四類:
1, active 活躍型: 當讀取通道空閒的時候發送心跳請求,一旦該心跳請求被髮送,那麼需要在keepAliveRequestTimeout時間內接收到心跳反饋,否則KeepAliveRequestTimeoutHandler將會被調用,當一個心跳請求包被接受到後,那麼心跳反饋也會立即發出。
針對活躍型心跳機制: KeepAliveMessageFactory 類的實現方法中: getRequest ( IoSession session)與getResponse ( IoSession session, Object request)必須返回非空。
2, semi-active 半活躍型:當讀取通道空閒的時候發送心跳請求,然而並不在乎心跳反饋有沒有,當一個心跳請求包被接收到後,那麼心跳反饋也會立即發出。
針對半活躍型心跳機制: KeepAliveMessageFactory 類的實現方法中: getRequest ( IoSession session)與getResponse ( IoSession session, Object request)必須返回非空。並且心跳包請求後超時無反饋的處理機制設置爲KeepAliveRequestTimeoutHandler.NOOP(不做任何處理), KeepAliveRequestTimeoutHandler.LOG(只輸出警告信息不做其他處理)
3, passive 被動型:當前IO不希望主動發送心跳請求,但是當接受到一個心跳請求後,那麼該心跳反饋也會立即發出。
針對被動型心跳機制: KeepAliveMessageFactory 類的實現方法中: getRequest ( IoSession session)必須反饋null 與 getResponse ( IoSession session, Object request)必須反饋non-null.
4, deaf speaker 聾子型: 當前IO會主動發送心跳請求,但是不想發送任何心跳反饋。
針對聾子型心跳機制: KeepAliveMessageFactory 類的實現方法中: getRequest ( IoSession session)必須反饋non-null與 getResponse ( IoSession session, Object request)必須反饋null,將KeepAliveRequestTimeoutHandler 設置爲DEAF_SPEAKER.
5, sient-listener 持續監聽型:既不想發送心跳請求也不想發送心跳反饋。
針對持續監聽型心跳機制: KeepAliveMessageFactory 類的實現方法中: getRequest ( IoSession session)必須反饋null 與 getResponse ( IoSession session, Object request)必須反饋null.
心跳包請求超時後的處理機制:接口 KeepAliveRequestTimeoutHandler ,一般該處理主要是針對能夠發送心跳請求的心跳機制。
1.CLOSE:關閉連接
2,LOG:輸出 警告信息
3,NOOP:不做任何處理
4,EXCEPTION:拋出異常
5,DEAF_SPEAKER:一個特殊的處理,停止當前過濾器對對心跳反饋監聽,因此讓過濾器丟失請求超時的偵測功能。(讓其變成聾子)
6,keepAliveRequestTimeout(KeepAliveFilter filter, IoSession session); 自定義處理
下面對客戶端與服務端和分別舉個例子:
服務器:
以被動型心跳機制爲例,服務器在接受到客戶端連接以後被動接受心跳請求,當在規定時間內沒有收到客戶端心跳請求時 將客戶端連接關閉
主要代碼如下:
KeepAliveMessageFactoryImpl
kamfi = new KeepAliveMessageFactoryImpl();
實現 方法: public boolean isRequest(IoSession session, Object message):判斷是否心跳請求包 是的話返回true
public boolean isResponse(IoSession session, Object message):由於被動型心跳機制,沒有請求當然也就不關注反饋 因此直接返回false
public Object getRequest(IoSession session): 被動型心跳機制無請求 因此直接返回null
public Object getResponse(IoSession session, Object request) : 根據心跳請求request 反回一個心跳反饋消息 non-nul
說明: KeepAliveMessageFactoryImpl 爲 KeepAliveMessageFactory的一個實現類,其中的實現方法滿足被動型心跳機制。
實現 方法: public boolean isRequest(IoSession session, Object message):判斷是否心跳請求包 是的話返回true
public boolean isResponse(IoSession session, Object message):由於被動型心跳機制,沒有請求當然也就不關注反饋 因此直接返回false
public Object getRequest(IoSession session): 被動型心跳機制無請求 因此直接返回null
public Object getResponse(IoSession session, Object request) : 根據心跳請求request 反回一個心跳反饋消息 non-nul
說明: KeepAliveMessageFactoryImpl 爲 KeepAliveMessageFactory的一個實現類,其中的實現方法滿足被動型心跳機制。
KeepAliveFilter kaf = new KeepAliveFilter(kamfi, IdleStatus.BOTH_IDLE);
說明:實例化一個 KeepAliveFilter 過濾器,傳入 KeepAliveMessageFactory引用,IdleStatus參數爲 BOTH_IDLE,及表明如果當前連接的讀寫通道都空閒的時候在指定的時間間隔getRequestInterval後發送出發Idle事件。
說明:實例化一個 KeepAliveFilter 過濾器,傳入 KeepAliveMessageFactory引用,IdleStatus參數爲 BOTH_IDLE,及表明如果當前連接的讀寫通道都空閒的時候在指定的時間間隔getRequestInterval後發送出發Idle事件。
kaf.setForwardEvent(true); //idle事件回發 當session進入idle狀態的時候 依然調用handler中的idled方法
說明:尤其 注意該句話,使用了 KeepAliveFilter之後,IoHandlerAdapter中的 sessionIdle方法默認是不會再被調用的! 所以必須加入這句話 sessionIdle纔會被調用
說明:尤其 注意該句話,使用了 KeepAliveFilter之後,IoHandlerAdapter中的 sessionIdle方法默認是不會再被調用的! 所以必須加入這句話 sessionIdle纔會被調用
kaf.setRequestInterval(heartPeriod); //本服務器爲被定型心跳 即需要每10秒接受一個心跳請求 否則該連接進入空閒狀態
並且發出idled方法回調
說明:設置心跳包請求時間間隔,其實對於被動型的心跳機制來說,設置心跳包請求間隔貌似是沒有用的,因爲它是不會發送心跳包的,但是它會觸發 sessionIdle事件, 我們利用該方法,可以來判斷客戶端是否在該時間間隔內沒有發心跳包,一旦 sessionIdle方法被調用,則認爲 客戶端丟失連接並將其踢出 。因此其中參數 heartPeriod其實就是服務器對於客戶端的IDLE監控時間。
說明:設置心跳包請求時間間隔,其實對於被動型的心跳機制來說,設置心跳包請求間隔貌似是沒有用的,因爲它是不會發送心跳包的,但是它會觸發 sessionIdle事件, 我們利用該方法,可以來判斷客戶端是否在該時間間隔內沒有發心跳包,一旦 sessionIdle方法被調用,則認爲 客戶端丟失連接並將其踢出 。因此其中參數 heartPeriod其實就是服務器對於客戶端的IDLE監控時間。
//kaf.setRequestTimeout(5); //超時時間 如果當前發出一個心跳請求後需要反饋 若反饋超過此事件 默認則關閉連接
acceptor.getFilterChain().addLast("heart", kaf);
說明: 該過濾器加入到整個通信的過濾鏈中。
客戶端:
客戶端會定時發送心跳請求(注意定時時間必須小於,服務器端的IDLE監控時間),同時需要監聽心跳反饋,以此來判斷是否與服務器丟失連接。對於服務器的心跳請求不給與反饋。
主要代碼如下:
說明: 該過濾器加入到整個通信的過濾鏈中。
客戶端:
客戶端會定時發送心跳請求(注意定時時間必須小於,服務器端的IDLE監控時間),同時需要監聽心跳反饋,以此來判斷是否與服務器丟失連接。對於服務器的心跳請求不給與反饋。
主要代碼如下:
ClientKeepAliveFactoryImpl ckafi = new ClientKeepAliveFactoryImpl();
實現 方法: public boolean isRequest(IoSession session, Object message): 服務器不會給客戶端發送請求包,因此不關注請求包,直接返回false
public boolean isResponse(IoSession session, Object message):客戶端關注請求反饋,因此判斷mesaage是否是反饋包
public Object getRequest(IoSession session): 獲取心跳請求包 non-null
public Object getResponse(IoSession session, Object request) : 服務器不會給客戶端發送心跳請求,客戶端當然也不用反饋 該方法返回null
說明: ClientKeepAliveFactoryImpl 爲 KeepAliveMessageFactory的一個實現類。
KeepAliveFilter kaf = new KeepAliveFilter(ckafi, IdleStatus.READER_IDLE,KeepAliveRequestTimeoutHandler.CLOSE);
說明:實例化一個 KeepAliveFilter 過濾器,傳入 KeepAliveMessageFactory引用,IdleStatus參數爲 READER_IDLE ,及表明如果當前連接的讀通道空閒的時候在指定的時間間隔getRequestInterval後發送出心跳請求,以及發出Idle事件。 KeepAliveRequestTimeoutHandler設置爲CLOS表明,當發出的心跳請求在規定時間內沒有接受到反饋的時候則調用CLOSE方式 關閉連接
kaf.setForwardEvent(true);
說明:繼續調用 IoHandlerAdapter 中的 sessionIdle時間
kaf.setRequestInterval(HEART_INTERVAL);
說明:設置當連接的讀取通道空閒的時候,心跳包請求時間間隔
kaf.setRequestTimeout(HEART_TIMEOUT);
說明:設置心跳包請求後 等待反饋超時時間。 超過該時間後則調用KeepAliveRequestTimeoutHandler.CLOSE
connector.getFilterChain().addLast("heart", kaf);
說明:
該過濾器加入到整個通信的過濾鏈中。 實現 方法: public boolean isRequest(IoSession session, Object message): 服務器不會給客戶端發送請求包,因此不關注請求包,直接返回false
public boolean isResponse(IoSession session, Object message):客戶端關注請求反饋,因此判斷mesaage是否是反饋包
public Object getRequest(IoSession session): 獲取心跳請求包 non-null
public Object getResponse(IoSession session, Object request) : 服務器不會給客戶端發送心跳請求,客戶端當然也不用反饋 該方法返回null
說明: ClientKeepAliveFactoryImpl 爲 KeepAliveMessageFactory的一個實現類。
KeepAliveFilter kaf = new KeepAliveFilter(ckafi, IdleStatus.READER_IDLE,KeepAliveRequestTimeoutHandler.CLOSE);
說明:實例化一個 KeepAliveFilter 過濾器,傳入 KeepAliveMessageFactory引用,IdleStatus參數爲 READER_IDLE ,及表明如果當前連接的讀通道空閒的時候在指定的時間間隔getRequestInterval後發送出心跳請求,以及發出Idle事件。 KeepAliveRequestTimeoutHandler設置爲CLOS表明,當發出的心跳請求在規定時間內沒有接受到反饋的時候則調用CLOSE方式 關閉連接
kaf.setForwardEvent(true);
說明:繼續調用 IoHandlerAdapter 中的 sessionIdle時間
kaf.setRequestInterval(HEART_INTERVAL);
說明:設置當連接的讀取通道空閒的時候,心跳包請求時間間隔
kaf.setRequestTimeout(HEART_TIMEOUT);
說明:設置心跳包請求後 等待反饋超時時間。 超過該時間後則調用KeepAliveRequestTimeoutHandler.CLOSE
connector.getFilterChain().addLast("heart", kaf);