張衛(wèi)鋼 向 運(yùn) 袁夢(mèng)覺(jué)
(長(zhǎng)安大學(xué)信息工程學(xué)院,陜西西安 710064)
IO系統(tǒng)對(duì)應(yīng)用程序的性能有至關(guān)重要的影響[1]。為提高程序IO處理效率,Java平臺(tái)開(kāi)發(fā)了NIO技術(shù),它采用事件驅(qū)動(dòng)的非阻塞的方式管理IO,性能很高,但是直接使用難度很大。Mina應(yīng)用程序框架封裝了Java NIO技術(shù),降低了軟件開(kāi)發(fā)難度。其有限狀態(tài)機(jī)用直觀的表格或圖形代替復(fù)雜的邏輯,非常適合以事件驅(qū)動(dòng)的程序設(shè)計(jì)。如果使用得當(dāng),可以開(kāi)發(fā)出簡(jiǎn)單高效的服務(wù)器程序。
MINA全 稱 為Multi-purpose Infrastructure for Network Applications,即網(wǎng)絡(luò)應(yīng)用多功能框架。它使用Java NIO技術(shù),提供了一個(gè)基于傳輸層事件驅(qū)動(dòng)的異步API,能夠幫助用戶開(kāi)發(fā)出高效的高可靠性的網(wǎng)絡(luò)應(yīng)用程序。
NIO是Java平臺(tái)為解決傳統(tǒng)IO效率低下的問(wèn)題而開(kāi)發(fā)的一種新型IO技術(shù),它采用操作系統(tǒng)管理內(nèi)存和文件的方式管理IO,并將一些耗時(shí)的操作轉(zhuǎn)嫁給操作系統(tǒng),使IO效率有了很大提高。另外,NIO采用事件驅(qū)動(dòng)、非阻塞的方式[2],能在單線程中管理大量并發(fā)的網(wǎng)絡(luò)連接,提高了系統(tǒng)資源利用率。
Mina框架對(duì)NIO進(jìn)行了封裝,將真正的網(wǎng)絡(luò)通信與應(yīng)用程序隔離開(kāi)來(lái),人們只需要關(guān)心收發(fā)的數(shù)據(jù)和業(yè)務(wù)邏輯即可[3]。
有限狀態(tài)機(jī)是一種表示有限個(gè)狀態(tài)以及這些狀態(tài)之間的轉(zhuǎn)移和動(dòng)作等行為的數(shù)學(xué)模型[4]。狀態(tài)機(jī)中的狀態(tài)反映了系統(tǒng)從開(kāi)始到當(dāng)前時(shí)刻的所有輸入變化的累加結(jié)果;轉(zhuǎn)換函數(shù)表示狀態(tài)間的映射關(guān)系; 動(dòng)作是在給定時(shí)刻要進(jìn)行的活動(dòng)的描述。有限狀態(tài)機(jī)可以比較精確的刻畫(huà)軟件系統(tǒng)的行為,因此被廣泛用于很多領(lǐng)域模型系統(tǒng)的建立。
當(dāng)系統(tǒng)的行為由許多不同類型事件驅(qū)動(dòng),對(duì)特定事件的響應(yīng)取決于當(dāng)前系統(tǒng)狀態(tài)的時(shí),有限狀態(tài)機(jī)最為有用??梢詫⒂邢逘顟B(tài)機(jī)作為一種組織原理,用來(lái)設(shè)計(jì)實(shí)現(xiàn)事件驅(qū)動(dòng)程序內(nèi)復(fù)雜的行為。如果處理得當(dāng),有限狀態(tài)機(jī)可以使代碼簡(jiǎn)單、測(cè)試迅速、維護(hù)輕松。
Mina網(wǎng)絡(luò)應(yīng)用程序框架提供了基于狀態(tài)機(jī)的編程接口。本文以五子棋游戲服務(wù)器程序?yàn)槔?,?jiǎn)要介紹基于Mina狀態(tài)機(jī)的服務(wù)器設(shè)計(jì)實(shí)現(xiàn)方法。
有限狀態(tài)機(jī)的基本要素是它所響應(yīng)的事件及事件間的狀態(tài)。設(shè)計(jì)時(shí)需考慮在每個(gè)可能的狀態(tài)下某個(gè)事件是否可能發(fā)生;采取什么動(dòng)作來(lái)處理事件;處理后轉(zhuǎn)移到什么狀態(tài);轉(zhuǎn)換時(shí)需要記錄什么變量等。
五子棋游戲的客戶端共有四個(gè)狀態(tài):未登錄狀態(tài)、閑置狀態(tài)、等待狀態(tài)和游戲中狀態(tài)。
(1)未登錄狀態(tài)下,客戶端的事件有用戶登錄。服務(wù)器收到登錄請(qǐng)求后,反饋用戶列表信息,并將客戶端的狀態(tài)更新為閑置狀態(tài)。
(2)閑置狀態(tài)下,客戶端的事件有創(chuàng)建游戲和加入游戲。服務(wù)器收到創(chuàng)建游戲請(qǐng)求后,將客戶端狀態(tài)更新為等待狀態(tài)。服務(wù)器收到加入游戲請(qǐng)求后,為游戲雙方建立映射,給雙方反饋信息,并將雙方的狀態(tài)更新為游戲中。
(3)等待狀態(tài)下,客戶端的事件有放棄游戲。服務(wù)器收到放棄游戲請(qǐng)求后,更改該客戶端狀態(tài)為閑置狀態(tài)。
(4)游戲中狀態(tài)下,客戶端的事件有放棄游戲和游戲結(jié)束。放棄游戲事件與前面類似。如果服務(wù)器收到的是游戲結(jié)束命令,則反饋勝負(fù)信息,開(kāi)始下一局游戲,不更改客戶端狀態(tài)。系統(tǒng)的狀態(tài)轉(zhuǎn)換如圖1所示。
圖1 五子棋客戶端狀態(tài)轉(zhuǎn)換圖
(1)配置狀態(tài)
需要配置閑置狀態(tài)、等待狀態(tài)和游戲中等三個(gè)狀態(tài)。以閑置狀態(tài)為例,方法如下:
@State public static final String IDLE =“Idle”;
其他兩個(gè)狀態(tài)的定義與之類似。
(2)配置狀態(tài)轉(zhuǎn)換函數(shù)
在配置狀態(tài)之后,需要配置狀態(tài)轉(zhuǎn)換函數(shù)。每個(gè)事件對(duì)應(yīng)一個(gè)狀態(tài)轉(zhuǎn)換函數(shù)。以創(chuàng)建游戲?yàn)槔?/p>
public void createGame(IoSession session,CreateCommand createCMD){…… //創(chuàng)建游戲}
當(dāng)起始狀態(tài)為“in = IDLE”、發(fā)生事件“on = MESSAGE_RECEIVED”時(shí),該方法被調(diào)用,方法執(zhí)行后,系統(tǒng)狀態(tài)變更為“next= WAIT”。
(3)創(chuàng)建和配置編解碼器
編解碼器用于將收到的字節(jié)信息轉(zhuǎn)換為通信協(xié)議格式的命令對(duì)象。以創(chuàng)建游戲?yàn)槔?,如果收到的?shù)據(jù)以字符串“/creategame [inchess]”開(kāi)頭,則表明為“創(chuàng)建游戲”命令,我們將它封裝為createCMD對(duì)象。其他情況與此類似。
if(line.startsWith(“/creategame [inchess]”)){
//創(chuàng)建游戲
CreateCommand createCMD = new CreateCommand();
createCMD.msgReceived = line;
}
(4)配置Mina框架并創(chuàng)建狀態(tài)機(jī)代理
在設(shè)計(jì)好狀態(tài)機(jī)和自定義編解碼器后,我們需要將它們關(guān)聯(lián)到Mina框架中。在main()方法中,綁定自定義的編解碼器對(duì)象CommandDecoder和IoHandler的實(shí)例createIoHandler。createIoHandler實(shí)例是由狀態(tài)機(jī)對(duì)象創(chuàng)建的代理對(duì)象。
ProtocolCodecFilter pcf = new ProtocolCodecFilter(
new TextLineEncoder(), new CommandDecoder());acceptor.getFilterChain().addLast(“codec”, pcf);
acceptor.setHandler(createIoHandler());createIoHandler實(shí)例的核心代碼如下:
StateMachine sm = StateMachineFactory.getInstance(
IoHandlerTransition.class).create(ChessServer.IDLE, new ChessServer());
return new StateMachineProxyBuilder().setStateContextLookup(
new IoSessionStateContextLookup(new StateContextFactory() {public StateContext create() {
return new ChessServer.ChessContext();
}
})).create(IoHandler.class, sm);至此,一個(gè)基于Mina狀態(tài)機(jī)的五子棋游戲服務(wù)器程序就編寫(xiě)成功了。
在公網(wǎng)環(huán)境中,使用普通PC機(jī)模擬服務(wù)器進(jìn)行測(cè)試。當(dāng)客戶端個(gè)數(shù)在大約8000個(gè)時(shí),基于Mina狀態(tài)機(jī)的五子棋游戲服務(wù)器程序運(yùn)行正常。與之相比較的測(cè)試程序采用Java傳統(tǒng)IO開(kāi)發(fā),使用為每一個(gè)客戶端開(kāi)啟一個(gè)線程的方式來(lái)實(shí)現(xiàn)服務(wù)器的IO處理。在相同的硬件條件和網(wǎng)絡(luò)環(huán)境中,當(dāng)客戶端數(shù)量達(dá)到大約2500個(gè)時(shí),就會(huì)出現(xiàn)大量客戶端連接失敗的現(xiàn)象。
測(cè)試結(jié)果表明:基于Mina狀態(tài)機(jī)開(kāi)發(fā)的服務(wù)器程序,與基于Java傳統(tǒng)方式開(kāi)放的服務(wù)器程序相比,性能有了很大的提高。
相較于傳統(tǒng)方法,基于Mina狀態(tài)機(jī)的服務(wù)器設(shè)計(jì)方法使用了有限狀態(tài)機(jī)的設(shè)計(jì)模型,設(shè)計(jì)簡(jiǎn)單。同時(shí)又具有Mina框架高性能的優(yōu)點(diǎn),因此,是一種能夠幫助人們很方便地開(kāi)發(fā)出高性能、高訪問(wèn)量、復(fù)雜邏輯服務(wù)器程序的方法,具有較高的應(yīng)用價(jià)值。
[1]張華,范寶德.基于Java NIO的通信技術(shù)研究[J].濰坊學(xué)院學(xué)報(bào),2008,8(4):44-47.
[2]羅振興,徐大偉.基于Java新IO的Web安全網(wǎng)關(guān)[J].計(jì)算機(jī)工程,2007,33(6):107-109.
[3]楊鐵軍,徐和飛.一種基于MINA框架的數(shù)據(jù)通信平臺(tái)設(shè)計(jì)[J].微計(jì)算機(jī)信息,2009,25(11): 22-24
[4]李健俊,蔣一翔.基于有限狀態(tài)機(jī)的用戶權(quán)限隔離模型[J].計(jì)算機(jī)應(yīng)用,2013,33(1):149- 152.