最近開發一個項目需要用到Client(Android)透過Socket與Server通訊,網上有看到Apache封裝好的Socket通訊包,初步學習。 內容主要來源於(MINA官方教程(中文版)) 1.網路應用架構: 基於ApacheMINA的網路應用有三個層次,分別是I/O服務、I/O過濾器和I/ ...
最近開發一個項目需要用到Client(Android)透過Socket與Server通訊,網上有看到Apache封裝好的Socket通訊包,初步學習。
內容主要來源於(MINA官方教程(中文版))
1.網路應用架構:
基於ApacheMINA的網路應用有三個層次,分別是I/O服務、I/O過濾器和I/O處理器:
I/O服務:I/O服務用來執行實際的I/O操作。ApacheMINA已經提供了一系列支持不同協議的I/O服務,如TCP/IP、UDP/IP、串口和虛擬機內部的管道等。開發人員也可以實現自己的I/O服務。
I/O過濾器:I/O服務能夠傳輸的是位元組流,而上層應用需要的是特定的對象與數據結構。
I/O過濾器用來完成這兩者之間的轉換。I/O過濾器的另外一個重要作用是對輸入輸出的數據進行處理,滿足橫切的需求。多個I/O過濾器串聯起來,形成I/O過濾器鏈。
I/O處理器:I/O處理器用來執行具體的業務邏輯。對接收到的消息執行特定的處理。創建一個完整的基於ApacheMINA的網路應用,需要分別構建這三個層次。
2.完成Client代碼初始化四步驟:
//第一步:創建連接對象:
SocketConnector connector = new NioSocketConnector();
//第二步:給該連接對象設置處理對象:(IoHandlerAdapter)
ClientHandler handler = new ClientHandler();
connector.setHandler(handler);
// 第三步:添加過濾器:
connector.getFilterChain().addLast("codec",
new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"),
LineDelimiter.WINDOWS.getValue(), LineDelimiter.WINDOWS.getValue())));
//第四步:綁定即將通信對象:
connector.connect(new InetSocketAddress("192.168.1.101", 5260));
3. I/O服務(IoService是I/O服務的介面,繼承 IoAcceptor)
I/O服務用來執行真正的I/O操作,以及管理I/O會話。根據所使用的數據傳輸方式的不同,有不同的I/O服務的實現。由於I/O服務執行的是輸入和輸出兩種操作,實際上有兩種具體的子類型。一種稱為“I/O接受器(I/Oacceptor)”,用來接受連接,一般用在伺服器的實現中;另外一種稱為“I/O連接器(I/Oconnector)”,用來發起連接,一般用在客戶端的實現中。
表1.IoService中的重要方法方法說明
setHandler(IoHandlerhandler):設置I/O處理器。該I/O處理器會負責處理該I/O服務所管理的所有I/O會話產生的I/O事件。getFilterChain()獲取I/O過濾器鏈,可以對I/O過濾器進行管理,包括添加和刪除I/O過濾器。
getManagedSessions():獲取該I/O服務所管理的I/O會話。
I/O連接器 Code Example:
SocketConnectorconnector=newNioSocketConnector();
connector.setConnectTimeoutMillis(CONNECT_TIMEOUT);
connector.getFilterChain().addLast("logger",newLoggingFilter());
connector.getFilterChain().addLast("protocol",
newProtocolCodecFilter(newTetrisCodecFactory()));
ConnectFutureconnectFuture=connector.connect(newInetSocketAddress(host,port));
connectFuture.awaitUninterruptibly();
4.I/O會話(IoSession)
I/O會話表示一個活動的網路連接,與所使用的傳輸方式無關。I/O會話可以用來存儲用戶自定義的與應用相關的屬性。這些屬性通常用來保存應用的狀態信息,還可以用來在I/O過濾器和I/O處理器之間交換數據。I/O會話在作用上類似於Servlet規範中的HTTP會話。
表2.IoSession中的重要方法方法說明:
close(booleanimmediately):關閉當前連接。如果參數immediately為true的話,連接會等到隊列中所有的數據發送請求都完成之後才關閉;否則的話就立即關閉。
getAttribute(Objectkey):從I/O會話中獲取鍵為key的用戶自定義的屬性。
setAttribute(Objectkey,Objectvalue):將鍵為key,值為value的用戶自定義的屬性存儲到I/O會話中。
removeAttribute(Objectkey):從I/O會話中刪除鍵為key的用戶自定義的屬性。
write(Objectmessage):將消息對象message發送到當前連接的對等體。該方法是非同步的,當消息被真正發送到對等體的時候,IoHandler.messageSent(IoSession,Object)會被調用。如果需要的話,也可以等消息真正發送出去之後再繼續執行後續操作。
這個介面有如下常用的方法:
A. WriteFuture write(Object message):這個方法用於寫數據,該操作是非同步的。
B. CloseFuture close(boolean immediately):這個方法用於關閉IoSession,該操作也是非同步的,參數指定true 表示立即關閉,否則就在所有的寫操作都flush 之後再關閉。
C. Object setAttribute(Object key,Object value):這個方法用於給我們向會話中添加一些屬性,這樣可以在會話過程中都可以使用,類似於HttpSession 的setAttrbute()方法。IoSession 內部使用同步的HashMap 存儲你添加的自定義屬性。
5.I/O過濾器(IoFilterAdapter)
從I/O服務發送過來的所有I/O事件和請求,在到達I/O處理器之前,會先由I/O過濾器鏈中的I/O過濾器進行處理。過濾器可以在很多情況下使用,比如記錄日誌、性能分析、訪問控制、負載均衡和消息轉換等。過濾器非常適合滿足網路應用中各種橫切的非功能性需求。在一個基於ApacheMINA的網路應用中,一般存在多個過濾器。這些過濾器互相串聯,形成鏈條,稱為過濾器鏈。每個過濾器依次對傳入的I/O事件進行處理。當前過濾器完成處理之後,由過濾器鏈中的下一個過濾器繼續處理。當前過濾器也可以不調用下一個過濾器,而提前結束,這樣I/O事件就不會繼續往後傳遞。比如負責用戶認證的過濾器,如果遇到未認證的對等體發出的I/O事件,則會直接關閉連接。這可以保證這些事件不會通過此過濾器到達I/O處理器。
表3.IoFilter中與過濾器的生命周期相關的方法
init():當過濾器第一次被添加到過 濾器鏈中的時候,此方法被調用。用來完成過濾器的初始化工作。
onPreAdd(IoFilterChainparent,Stringname,IoFilter.NextFilternextFilter): 當過濾器即將被添加到過濾 器鏈中的時候,此方法被調用。
onPostAdd(IoFilterChainparent,String name,IoFilter.NextFilternextFilter):當過濾器已經被添加到過濾器鏈中之後,此方法被調用
onPreRemove(IoFilterChainparent,Stringname,IoFilter.NextFilternextFilter):當過濾器即將被從過濾器鏈中刪除的時候,此方法被調用。
onPostRemove(IoFilterChainparent,Stringname,IoFilter.NextFilternextFilter):當過濾器已經被從過濾器鏈中刪除的時候,此方法被調用。
destroy():當過濾器不再需要的時候,它將被銷毀,此方法被調用
參數parent表示包含此過濾器的過濾器鏈,參數name表示過濾器的名稱,參數nextFilter表示過濾器鏈中的下一個過濾器。
filterClose(IoFilter.NextFilternextFilter,IoSessionsession):濾對IoSession的close方法的調用。
filterWrite(IoFilter.NextFilternextFilter,IoSessionsession,WriteRequestwriteRequest):濾對IoSession的write方法的調用。
exceptionCaught(IoFilter.NextFilternextFilter,IoSessionsession,Throwablecause):濾對IoHandler的exceptionCaught方法的調用。
messageReceived(IoFilter.NextFilternextFilter,IoSessionsession,Objectmessage):過濾對IoHandler的messageReceived方法的調用。
messageSent(IoFilter.NextFilternextFilter,IoSessionsession,WriteRequestwriteRequest):過濾對IoHandler的messageSent方法的調用。
sessionClosed(IoFilter.NextFilternextFilter,IoSessionsession):過濾對IoHandler的sessionClosed方法的調用。
sessionCreated(IoFilter.NextFilternextFilter,IoSessionsession):過濾對IoHandler的sessionCreated方法的調用。
sessionIdle(IoFilter.NextFilternextFilter,IoSessionsession,IdleStatusstatus):過濾對IoHandler的sessionIdle方法的調用。
sessionOpened(IoFilter.NextFilternextFilter,IoSessionsession):過濾對IoHandler的sessionOpened方法的調用。
code example:
public void messageReceived(NextFilternextFilter,IoSessionsession,Objectmessage){
if(!isON(session)){
nextFilter.messageReceived(session,message);
}else{
endSession(session);
}
}
private void endSession(IoSessionsession){
session.close(true);
}
6.過濾器鏈(IoFilterChain)
過濾器只有在添加到過濾器鏈中的時候才起作用。過濾器鏈是過濾器的容器。過濾器鏈與I/O會話是一一對應的關係.
IoFilterChain介面的方法方法說明:
addFirst(String name,IoFilterfilter filter):將指定名稱的過濾器添加到過濾器鏈的開頭。
addLast(String name,IoFilterfilter filter):將指定名稱的過濾器添加到過濾器鏈的末尾。
contains(String name)判斷過濾器鏈中是否包含指定名稱的過濾器。
get(String name):從過濾器鏈中獲取指定名稱的過濾器。
remove(String name):從過濾器鏈中刪除指定名稱的過濾器。
replace(String name,IoFilter newFilter):用過濾器newFilter替換掉過濾器鏈中名為name的過濾器。
getSession():獲取與過濾器鏈一一對應的I/O會話
7.I/O處理器(IoHandlerAdapter)
I/O事件通過過濾器鏈之後會到達I/O處理器。I/O處理器中與I/O事件對應的方法會被調用。ApacheMINA中org.apache.mina.core.service.IoHandler是I/O處理器要實現的介面,一般情況下,只需要繼承自org.apache.mina.core.service.IoHandlerAdapter並覆寫所需方法即可。
IoHandler介面的方法:
sessionCreated(IoSessionsession)當有新的連接建立的時候,該方法被調用。
sessionOpened(IoSessionsession)當有新的連接打開的時候,該方法被調用。該方法在sessionCreated之後被調用。
sessionClosed(IoSessionsession)當連接被關閉的時候,此方法被調用。
sessionIdle(IoSessionsession,IdleStatusstatus)當連接變成閑置狀態的時候,此方法被調用。
exceptionCaught(IoSessionsession,Throwablecause)當I/O處理器的實現或是ApacheMINA中有異常拋出的時候,此方法被調用。
messageReceived(IoSessionsession,Objectmessage)當接收到新的消息的時候,此方法被調用。
messageSent(IoSessionsession,Objectmessage)當消息被成功發送出去的時候,此方法被調用。
其中
1.sessionCreated和sessionOpened的區別:
sessionCreated方法是由I/O處理線程來調用的,而sessionOpened是由其它線程來調用的。因此從性能方面考慮,不要在sessionCreated方法中執行過多的操作。
2.sessionIdle,預設情況下,閑置時間設置是禁用的,也就是說sessionIdle並不會被調用。可以通過IoSessionConfig.setIdleTime(IdleStatus,int)來進行設置
常用方法:
1. WriteFuture的使用
IoSessionsession=...;//獲取I/O會話對象
WriteFuturefuture=session.write("HelloWorld");//發送數據
future.awaitUninterruptibly();//等待發送數據操作完成
if(future.isWritten()){
//數據已經被成功發送}else{
//數據發送失敗}
由於這樣的需求很常見,I/O處理器中提供了messageSent方法,當數據發送成功的時候,該方法會被調用。
2. JMX集成ApacheMINA可以集成JMX來對網路應用進行管理和監測。
MBeanServermBeanServer=ManagementFactory.getPlatformMBeanServer();
IoAcceptoracceptor=newNioSocketAcceptor();
IoServiceMBeanacceptorMBean=newIoServiceMBean(acceptor);
ObjectNameacceptorName=newObjectName(acceptor.getClass().getPackage().getName()+":type=acceptor,name="+acceptor.getClass().getSimpleName));
mBeanServer.registerMBean(acceptorMBean,acceptorName);