基于MINA框架快速開(kāi)發(fā)網(wǎng)絡(luò )應用程序
1.MINA框架簡(jiǎn)介
MINA(Multipurpose Infrastructure for Network Applications)是用于開(kāi)發(fā)高性能和高可用性的網(wǎng)絡(luò )應用程序的基礎框架。通過(guò)使用MINA框架可以可以省下處理底層I/O和線(xiàn)程并發(fā)等復雜工作,開(kāi)發(fā)人員能夠把更多的精力投入到業(yè)務(wù)設計和開(kāi)發(fā)當中。MINA框架的應用比較廣泛,應用的開(kāi)源項目有Apache Directory、AsyncWeb、Apache Qpid、QuickFIX/J、Openfire、SubEthaSTMP、red5等。MINA框架當前穩定版本是1.1.6,最新的2.0版本目前已經(jīng)發(fā)布了M1版本。
MINA框架的特點(diǎn)有:基于java NIO類(lèi)庫開(kāi)發(fā);采用非阻塞方式的異步傳輸;事件驅動(dòng);支持批量數據傳輸;支持TCP、UDP協(xié)議;控制反轉的設計模式(支持Spring);采用優(yōu)雅的松耦合架構;可靈活的加載過(guò)濾器機制;單元測試更容易實(shí)現;可自定義線(xiàn)程的數量,以提高運行于多處理器上的性能;采用回調的方式完成調用,線(xiàn)程的使用更容易。
2.MINA框架的常用類(lèi)
類(lèi)NioSocketAcceptor用于創(chuàng )建服務(wù)端監聽(tīng);
類(lèi)NioSocketConnector用于創(chuàng )建客戶(hù)端連接;
類(lèi)IoSession用來(lái)保存會(huì )話(huà)屬性和發(fā)送消息;
類(lèi)IoHandlerAdapter用于定義業(yè)務(wù)邏輯,常用的方法有:
方法 定義
sessionCreated() 當會(huì )話(huà)創(chuàng )建時(shí)被觸發(fā)
sessionOpened() 當會(huì )話(huà)開(kāi)始時(shí)被觸發(fā)
sessionClosed() 當會(huì )話(huà)關(guān)閉時(shí)被觸發(fā)
sessionIdle() 當會(huì )話(huà)空閑時(shí)被觸發(fā)
exceptionCaught() 當接口中其他方法拋出異常未被捕獲時(shí)觸發(fā)此方法
messageRecieved() 當接收到消息后被觸發(fā)
messageSent() 當發(fā)送消息后被觸發(fā)
3.服務(wù)端應用開(kāi)發(fā)示例
下面將以MINA2.0M1版本為基礎,通過(guò)一個(gè)范例來(lái)演示一下如何使用MINA框架進(jìn)行開(kāi)發(fā)。開(kāi)發(fā)環(huán)境為jdk6.0,開(kāi)發(fā)工具NetBeans6.0,所需jar包slf4j-api.jar、slf4j-jdk14.jar、MINA-core-2.0.0-M1.jar。
首先定義一個(gè)業(yè)務(wù)邏輯處理器TimeServerHandler,繼承自IoHandlerAdapter,實(shí)現的功能有:當客戶(hù)端創(chuàng )建會(huì )話(huà)時(shí)會(huì )顯示客戶(hù)端設備的IP和端口;當客戶(hù)端輸入quit時(shí)結束會(huì )話(huà);客戶(hù)端輸入其它內容時(shí)則向客戶(hù)端發(fā)送當前時(shí)間。代碼如下:
public class TimeServerHandler extends IoHandlerAdapter
{
@Override
public void sessionCreated(IoSession session) {
//顯示客戶(hù)端的ip和端口
System.out.println(session.getRemoteAddress().toString());
}
@Override
public void messageReceived( IoSession session, Object message ) throws Exception
{
String str = message.toString();
if( str.trim().equalsIgnoreCase("quit") ) {
session.close();//結束會(huì )話(huà)
return;
}
Date date = new Date();
session.write( date.toString() );//返回當前時(shí)間的字符串
System.out.println("Message written...");
}
}
再定義一個(gè)類(lèi)MinaTimeServer用來(lái)啟動(dòng)服務(wù)端:
public class MinaTimeServer
{
private static final int PORT = 9123;//定義監聽(tīng)端口
public static void main( String[] args ) throws IOException
{
IoAcceptor acceptor = new NioSocketAcceptor();
acceptor.getFilterChain().addLast( "logger", new LoggingFilter() );
acceptor.getFilterChain().addLast( "codec", new ProtocolCodecFilter( new TextLineCodecFactory( Charset.forName( "UTF-8" ))));//指定編碼過(guò)濾器
acceptor.setHandler( new TimeServerHandler() );//指定業(yè)務(wù)邏輯處理器
acceptor.setDefaultLocalAddress( new InetSocketAddress(PORT) );//設置端口號
acceptor.bind();//啟動(dòng)監聽(tīng)
}
}
4.測試
首先運行MinaTimeServer,啟動(dòng)服務(wù)端,接著(zhù)在命令行運行“telnet 127.0.0.1 9123”,來(lái)登錄,這時(shí)會(huì )看到服務(wù)端輸出如下:
2008-2-21 16:15:29 org.apache.MINA.filter.logging.LogLevel$4 log
/10.64.2.137:4140 ?IP和端口號
信息: CREATED
2008-2-21 16:15:29 org.apache.MINA.filter.logging.LogLevel$4 log
信息: OPENED 在客戶(hù)端輸入回車(chē),在客戶(hù)端可以看到服務(wù)端返回當前的時(shí)間:
Thu Feb 21 16:20:14 CST 2008
服務(wù)端輸出:
2008-2-21 16:20:14 org.apache.MINA.filter.logging.LogLevel$4 log
信息: RECEIVED: HeapBuffer[pos=0 lim=2 cap=2048: 0D 0A] ?接收收到回車(chē)符
Message written...
2008-2-21 16:20:14 org.apache.MINA.filter.logging.LogLevel$4 log
信息: SENT: HeapBuffer[pos=0 lim=29 cap=30: 54 68 75 20 46 65 62 20 32 31 20 31 36 3A 32 30...]
2008-2-21 16:20:14 org.apache.MINA.filter.logging.LogLevel$4 log
信息: SENT: HeapBuffer[pos=0 lim=0 cap=0: empty] 5.客戶(hù)端開(kāi)發(fā)示例
首先定義類(lèi)TimeClientHandler來(lái)處理消息接收事件:
class TimeClientHandler extends IoHandlerAdapter{
public TimeClientHandler() {
}
@Override
public void messageReceived(IoSession session, Object message) throws Exception {
System.out.println(message);//顯示接收到的消息
}
}
接著(zhù)定義MinaTimeClient類(lèi)用于連接服務(wù)端,并向服務(wù)端發(fā)送消息:
public class MinaTimeClient {
public static void main(String[] args) {
// 創(chuàng )建客戶(hù)端連接器.
NioSocketConnector connector = new NioSocketConnector();
connector.getFilterChain().addLast( "logger", new LoggingFilter() );
connector.getFilterChain().addLast( "codec", new ProtocolCodecFilter( new TextLineCodecFactory( Charset.forName( "UTF-8" )))); //設置編碼過(guò)濾器
connector.setConnectTimeout(30);
connector.setHandler(new TimeClientHandler());//設置事件處理器
ConnectFuture cf = connector.connect(
new InetSocketAddress("127.0.0.1", 9123));//建立連接
cf.awaitUninterruptibly();//等待連接創(chuàng )建完成
cf.getSession().write("hello");//發(fā)送消息
cf.getSession().write("quit");//發(fā)送消息
cf.getSession().getCloseFuture().awaitUninterruptibly();//等待連接斷開(kāi)
connector.dispose();
}
}
6.總結
通過(guò)上述示例可以了解到:使用MINA框架來(lái)開(kāi)發(fā)的網(wǎng)絡(luò )應用程序代碼結構更清晰;MINA框架完成了底層的線(xiàn)程管理;MINA內置的編碼器可以滿(mǎn)足大多數用戶(hù)的需求,省去了開(kāi)發(fā)人員消息編碼解碼的工作。具稱(chēng)使用MINA開(kāi)發(fā)服務(wù)器程序的性能已經(jīng)逼近使用 C/C++ 語(yǔ)言開(kāi)發(fā)的網(wǎng)絡(luò )服務(wù)。因此,建議在網(wǎng)絡(luò )應用程序開(kāi)發(fā)過(guò)程中嘗試使用MINA框架來(lái)提高我們的開(kāi)發(fā)效率和應用程序的執行效率。
網(wǎng)通系統集成公司 楊慶成