夢幻之旅
DEBUG - 天道酬勤
::
首頁
::
新隨筆
::
聯系
::
聚合
::
管理
::
671 隨筆 :: 6 文章 :: 256 評論 :: 0 Trackbacks
<
2011年9月
>
日
一
二
三
四
五
六
28
29
30
31
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
1
2
3
4
5
6
7
8
公告
本博客中未注原創的文章均為轉載,對轉載內容可能做了些修改和增加圖片注釋,如果侵犯了您的版權,或沒有注明原作者,請諒解
常用鏈接
我的隨筆
我的評論
我的參與
最新評論
留言簿
(21)
給我留言
查看公開留言
查看私人留言
隨筆分類
(644)
Android(10)
(rss)
ANT(4)
(rss)
C#(10)
(rss)
C/C++(16)
(rss)
CSS(3)
(rss)
DataBase(119)
(rss)
DB-DailyMmaintenance(16)
(rss)
Design Patterns(27)
(rss)
english
(rss)
Exceptions(7)
(rss)
EXT(39)
(rss)
FLASH(9)
(rss)
Hardware(20)
(rss)
Hibernate(13)
(rss)
Html(23)
(rss)
Java(143)
(rss)
java Net(10)
(rss)
JavaScript(39)
(rss)
Linux(26)
(rss)
php(5)
(rss)
Regular Exp(3)
(rss)
Spring(17)
(rss)
Struts(12)
(rss)
TOOL(43)
(rss)
VB/VBA/VBS(5)
(rss)
webservice(9)
(rss)
XML(2)
(rss)
我的夢幻旅途(14)
(rss)
隨筆檔案
(669)
2017年9月 (4)
2016年10月 (1)
2015年6月 (1)
2015年4月 (2)
2015年1月 (1)
2014年8月 (2)
2014年7月 (9)
2014年6月 (1)
2014年5月 (2)
2014年4月 (3)
2014年3月 (3)
2013年10月 (4)
2013年9月 (8)
2013年8月 (4)
2013年6月 (3)
2013年5月 (4)
2013年4月 (7)
2013年3月 (1)
2013年1月 (3)
2012年12月 (4)
2012年11月 (1)
2012年10月 (1)
2012年9月 (4)
2012年8月 (1)
2012年7月 (2)
2012年6月 (1)
2012年5月 (4)
2012年4月 (2)
2012年3月 (1)
2012年2月 (4)
2012年1月 (6)
2011年12月 (10)
2011年11月 (7)
2011年10月 (6)
2011年9月 (37)
2011年8月 (34)
2011年7月 (44)
2011年6月 (10)
2011年5月 (5)
2011年4月 (3)
2011年3月 (1)
2011年2月 (1)
2011年1月 (18)
2010年12月 (9)
2010年11月 (13)
2010年10月 (17)
2010年9月 (2)
2010年8月 (10)
2010年7月 (10)
2010年6月 (5)
2010年5月 (8)
2010年4月 (9)
2010年3月 (11)
2010年2月 (3)
2010年1月 (8)
2009年12月 (6)
2009年11月 (10)
2009年10月 (5)
2009年9月 (1)
2009年8月 (18)
2009年7月 (6)
2009年6月 (2)
2009年5月 (1)
2009年4月 (4)
2009年3月 (6)
2009年2月 (5)
2009年1月 (3)
2008年12月 (13)
2008年11月 (13)
2008年10月 (30)
2008年9月 (9)
2008年8月 (24)
2008年7月 (17)
2008年6月 (15)
2008年5月 (16)
2008年4月 (15)
2008年3月 (19)
2008年2月 (3)
2008年1月 (20)
2007年12月 (24)
2007年11月 (9)
文章檔案
(6)
2008年4月 (1)
2008年3月 (1)
2008年1月 (2)
2007年11月 (2)
最新隨筆
1.?PP代碼生成器(四) 使用解決方案生成代碼
2.? PP代碼生成器(三) 設計freemarker模板, 創建解決方案
3.? PP代碼生成器(二) 解決方案, 生成任務, 輔助設計面板
4.? PP代碼生成器(一) 簡介, 下載, 運行
5.?PP持久層代碼生成器
6.?比較好的博客
7.?系統集成項目管理工程師
8.?軟件公司項目經理崗位職責
9.?聯想筆記本 顯示屏 鍵盤失靈 釋放靜電
10.?eclipse maven
積分與排名
積分 - 960736
排名 - 37
最新評論
1.?re: Myeclipse 快捷鍵大全(絕對全)
crl+向右箭頭(輸入法有問題打不出來)移到下一個參數的位置,然后crl+shift+向右箭頭 選中該位置的參數即可
--紅領巾
2.?re: Log4j基本使用方法
555
--555
3.?re: Myeclipse 快捷鍵大全(絕對全)[未登錄]
很不錯,謝謝
--銀狐
4.?re: Flex 表單
是誰這么無聊~嗚~~~
--HUIKK
5.?re: Spring AfterReturning 異常
具體是什么意思啊
--dingli
閱讀排行榜
1.?Exception in thread "main" java.lang.NoClassDefFoundError: com/sun/mail/util/LineInputStream(70034)
2.?log4j.properties 使用說明(42086)
3.?Myeclipse 快捷鍵大全(絕對全)(32737)
4.?TNSNAMES.ORA 配置(24399)
5.?oracle 樹狀查詢(21366)
評論排行榜
1.?Exception in thread "main" java.lang.NoClassDefFoundError: com/sun/mail/util/LineInputStream(53)
2.?JMail 異常: java.lang.NoClassDefFoundError: javax/activation/DataSource(21)
3.?javax.mail.MessagingException: 530 5.7.0 Must issue a STARTTLS command first(14)
4.?java 讀取 excel 2003 或 excel 2007(14)
5.?java.lang.UnsupportedClassVersionError: Bad version number in .class file(8)
(轉)MINA2 之IoBuffer
最近做的一個項目用到了開源的C
/
S應用的服務器框架MINA,當初做的時候資料非常少,只能自己不停的測試,總結出了一些規律經驗。
從網上看的資料上看,這個服務器框架還是比較穩定和支持的并發數還是很不錯的,不過沒有準確的數據,而且我做完的時候也沒有拿到真正的實際環境中測試過,用的時候也發現了很多優點和缺點,使用者可以自己去根據自己的使用需求去衡量是否使用該框架。
服務器是商業系統很重要的一部分,主要負責數據采集,文件分發,與端機的通信,和自動作業等任務,服務器大多是24小時運行的,因此服務器的實現必須強壯、穩定、安全,而速度雖然也是很重要,不過最重要的還是前三者。服務器框架MINA就是要為這樣的服務器提供了一個網絡應用框架,當然這樣的服務器框架也可以自己去實現。MINA為我們封裝了socket的底層通信實現,提供了日志,線程池等功能,使用起來非常簡單、方便。
MINA是一個異步框架,是通過網絡事件激發的,它包含兩層:IO層和協議層。首先介紹IO層,要說明的是我用的版本是0.
8.2
,可能不同版本會稍有不同。
Client產生一個底層IO事件,比如說連接和發送數據包,IoAcceptor執行所有底層IO,將他們翻譯成抽象的IO事件,接著這里可以添加(也可以部添加)一個IoFilters對IO事件進行過濾,并把翻譯過的事件或過濾過的事件和關聯的IoSession 發送給IoHandler。IoSession是一個有效的網絡連接會話,此會話將一直保持連接,除非網絡斷開或用戶主動斷開連接(session.close()),用戶可以通過IoSession獲得有關該會話連接的信息和配置會話的對象和屬性;IoHandler是網絡事件的監聽器,也就是說當有網絡事件發生時會通知IoHandler,用戶不用去主動接受數據。用戶只要實現此接口愛干嗎干嗎去吧。IoFilter:Io過濾器,對Io事件進行過濾,比如添加日志過濾器和線程池過濾器。
使用說明:
import
java.util.logging.Level;
import
org.apache.mina.common.ByteBuffer;
import
org.apache.mina.common.IdleStatus;
import
org.apache.mina.common.SessionConfig;
import
org.apache.mina.io.IoHandlerAdapter;
import
org.apache.mina.io.IoSession;
import
org.apache.mina.io.socket.SocketSessionConfig;
import
org.apache.mina.util.SessionLog;
public
class
ServerHandler
extends
IoHandlerAdapter
{
public
ServerHandler()
{
}
public
void
dataRead(IoSession session, ByteBuffer buffer)
throws
Exception
{
//
當有數據讀入時此方法被調用,數據封裝在ByteBuffer中,可以用以下方法對出buffer的數據,ByteBuffer的數據讀出后內存中就沒有了。
//
String message = "";
//
byte[] bytes = new byte[rb.remaining()];
//
int j = 0;
//
while (rb.hasRemaining()) {
//
bytes[j++] = rb.get();
//
}
//
message = new String(bytes);
//
接著可以進行邏輯處理
}
public
void
dataWritten(IoSession session, Object mark)
throws
Exception
{
//
當數據被寫入通道時此方法被調用,實際就是調用了session.write(IoSession,Object)方法
SessionLog.log(Level.INFO,session,mark.toString());
//
必要時打印所寫入的內容,mark的內容就是session.write(session,mark)中的第二個參數
}
public
void
exceptionCaught(IoSession session, Throwable arg1)
throws
Exception
{
//
當出現異常時此方法被調用,從而進行各種異常處理,該方法可以捕捉網絡異常(如連接非正常關閉)和所有其他方法產生的異常,這里要注意如果客戶端要保持與服務器端的連接時不要在這里馬上重新連接不然會拋出CancelKeyException運行期異常直接導致程序死掉(特別是與服務器端有超過兩個連接時一定會發生并且此異常無法捕獲),建議的方法是啟動一個單獨的線程來完成與服務器端的重新連接,還有要注意的是如果網絡是正常關閉的,比如說是客戶端正常關閉連接,而此時服務器端是不愿意關閉的話,這個異常本方法是捕捉不了的,因此只能在session.close()方法中處理這種情況。
session.close();
}
public
void
sessionClosed(IoSession session)
throws
Exception
{
//
當網絡連接被關閉是此方法被調用
SessionLog.log(Level.INFO,session,
"
Close a Session
"
);
//
必要時打印出信息
}
public
void
sessionCreated(IoSession session)
throws
Exception
{
//
當網絡連接被創建時此方法被調用(這個肯定在sessionOpened(IoSession session)方法之前被調用),這里可以對Socket設置一些網絡參數
SessionConfig cfg
=
session.getConfig();
if
(cfg
instanceof
SocketSessionConfig)
{
((SocketSessionConfig) cfg).setSessionReceiveBufferSize(
2048
);
((SocketSessionConfig) cfg).setKeepAlive(
true
);
((SocketSessionConfig) cfg).setSoLinger(
true
,
0
);
((SocketSessionConfig) cfg).setTcpNoDelay(
true
);
((SocketSessionConfig) cfg).setWriteTimeout(
1000
*
5
);
}
}
public
void
sessionIdle(IoSession arg0, IdleStatus arg1)
throws
Exception
{
//
當網絡通道空閑時此方法被調用,在這里可以判斷是讀空閑、寫空閑還是兩個都空閑,以便做出正確的處理
一半的網絡通訊程序都要與服務器端保持長連接,所以這里可以發一下網絡測試數據以保持與服務器端的連接
}
public
void
sessionOpened(IoSession session)
throws
Exception
{
//
當網絡連接被打開時此方法被調用,這里可以對session設置一些參數或者添加一些IoFilter的實現,也可以對客戶端做一些認證之類的工作
session.getConfig().setIdleTime(IdleStatus.BOTH_IDLE,
60
);
}
}
//
啟動監聽連接的服務器
import
org.apache.mina.common.
*
;
import
org.apache.mina.io.
*
;
import
org.apache.mina.io.filter.
*
;
import
org.apache.mina.registry.
*
;
public
class
Server
{
/** */
/**
Choose your favorite port number.
*/
private
static
final
int
PORT
=
8080
;
public
static
void
main( String[] args )
throws
Exception
{
ServiceRegistry registry
=
new
SimpleServiceRegistry();
//
可以添加各種過濾器,比如線程池過濾器,增加一個線程池處理來自不同的連接
IoAcceptor ioAcceptor
=
registry.getIoAcceptor();
IoThreadPoolFilter ioThreadPoolFilter
=
new
IoThreadPoolFilter();
ioThreadPoolFilter.setMaximumPoolSize(
10
);
ioThreadPoolFilter.start();
ioAcceptor.getFilterChain().addLast(
"
IoThreadPool
"
,
ioThreadPoolFilter);
//
Bind
Service service
=
new
Service(
"
serviceName
"
,
TransportType.SOCKET, PORT );
registry.bind( service,
new
ServerHandler() );
System.out.println(
"
Listening on port
"
+
PORT );
}
}
//
如果是連接服務器的可以如下啟動連接請求
import
org.apache.mina.io.filter.IoThreadPoolFilter;
import
org.apache.mina.io.socket.SocketConnector;
import
java.net.InetSocketAddress;
public
class
Client
{
public
static
void
main( String[] args )
throws
Exception
{
private
static
final
int
CONNECT_TIMEOUT
=
3
;
//
設置超時連接時間
//
可以添加各種過濾器,比如線程池過濾器,增加一個線程池處理來自不同的連接
IoThreadPoolFilter ioThreadPoolFilter
=
new
IoThreadPoolFilter();
ioThreadPoolFilter.setMaximumPoolSize(
10
);
ioThreadPoolFilter.start();
SocketConnector connector
=
new
SocketConnector();
connector.getFilterChain().addFirst(
"
threadPool
"
,
ioThreadPoolFilter);
//
初始化客戶端的監聽處理器
ClientHandler clientHandler
=
new
ClientHandler();
InetSocketAddress address
=
new
InetSocketAddress(
"
serverIp
"
,serverPort);
try
{
connector.connect(address, CONNECT_TIMEOUT,
clientHandler);
System.out.println(
"
connect sucessfully!
"
);
}
catch
(Exception e)
{
System.err.println(
"
Failed to connect.
"
);
}
}
如果一個協議非常復雜,如果只用一個Io層是非常復雜的,因為IO層沒有幫助你分離‘message解析’和‘實際的業務邏輯,MINA提供了一個協議層來解決這個問題。
使用協議層必須實現5個接口:ProtocolHandler, ProtocolProvider, ProtocolCodecFactory, ProtocolEncoder, 和 ProtocolDecoder:
第一步:實現ProtocolDecoder和ProtocolEncoder,當有IO事件時便先調用這兩個類的方法
import
org.apache.mina.common.ByteBuffer;
import
org.apache.mina.protocol.ProtocolDecoderOutput;
import
org.apache.mina.protocol.ProtocolSession;
import
org.apache.mina.protocol.ProtocolViolationException;
import
org.apache.mina.protocol.codec.MessageDecoder;
import
org.apache.mina.protocol.codec.MessageDecoderResult;
import
java.util.
*
;
public
class
ServerDecoder
implements
MessageDecoder
{
public
ServerTranInfoDecoder()
{
}
public
MessageDecoderResult decodable(ProtocolSession session, ByteBuffer in)
{
//
對接受的數據判斷是否與協議相同,如果相同返回MessageDecoderResult.OK,否則返回MessageDecoderResult.NOT_OK,這里如果要從ByteBuffer讀出數據,需要重新用ByteBuffer.put(ByteBuffer)放回內存中,以便decode方法使用;
return
MessageDecoderResult.OK;
return
MessageDecoderResult.NOT_OK;
}
public
MessageDecoderResult decode(ProtocolSession session, ByteBuffer in,
ProtocolDecoderOutput out)
throws
ProtocolViolationException
{
//
根據協議將介紹到的數據(放在ByteBuffer中)組裝成相對應的實體,調用out.write(Object)方法發送給協議層進行業務邏輯的處理,如果成功返回MessageDecoderResult.OK,否則返回MessageDecoderResult.NOT_OK;
out.write(object);
}
import
org.apache.mina.common.ByteBuffer;
import
org.apache.mina.protocol.ProtocolEncoderOutput;
import
org.apache.mina.protocol.ProtocolSession;
import
org.apache.mina.protocol.ProtocolViolationException;
import
org.apache.mina.protocol.codec.MessageEncoder;
import
java.util.
*
;
public
class
ServerEncoder
implements
MessageEncoder
{
public
static
Set TYPES;
public
ServerEncoder()
{
}
public
Set getMessageTypes()
{
HashSet set
=
new
HashSet();
set.add(Send.
class
);
//
增加要進行編碼的實體類
TYPES
=
Collections.unmodifiableSet( set );
return
TYPES;
}
public
void
encode( ProtocolSession session, Object message, ProtocolEncoderOutput out )
throws
ProtocolViolationException
{
//
將回應報文實體message編碼層returnStr后發送到客戶端
byte
[] bytes
=
returnStr.getBytes();
ByteBuffer rb
=
ByteBuffer.allocate(bytes.length);
rb.put(bytes);
rb.flip();
out.write(rb);
}
}
第二步:實現ProtocolCodecFactory
import
org.apache.mina.protocol.codec.DemuxingProtocolCodecFactory;
public
class
ServerProtocolCodecFactory
extends
DemuxingProtocolCodecFactory
{
public
ServerProtocolCodecFactory(
boolean
server)
{
if
(server)
{
super
.register(ServerDecoder.
class
);
super
.register(ServerEncoder.
class
);
}
}
}
第三步:實現ProtocolHandler,在有IO事件發生后,經過decode和encode的處理后就把協議實體交個這個處理器進行業務邏輯的處理,因此實現了協議解釋和業務邏輯的分離,它與IoHandler非常相似,不過這里處理的是經過編碼與解碼后的對象實體。
import
org.apache.mina.common.IdleStatus;
import
org.apache.mina.protocol.ProtocolSession;
import
org.apache.mina.util.SessionLog;
import
org.apache.mina.protocol.handler.DemuxingProtocolHandler;
public
class
ServerSessionHandler
extends
DemuxingProtocolHandler
{
public
ServerSessionHandler()
{
}
public
void
sessionCreated(ProtocolSession session)
throws
Exception
{
}
public
void
sessionOpened(ProtocolSession session)
throws
Exception
{
session.getConfig().setIdleTime(IdleStatus.BOTH_IDLE,
60
);
}
public
void
sessionClosed(ProtocolSession session)
{
}
public
void
messageReceived(ProtocolSession session, Object message)
throws
Exception
{
//
根據解碼后的message,進行業務邏輯的處理
session.close();
}
public
void
messageSent(ProtocolSession session, Object message)
{
}
public
void
sessionIdle(ProtocolSession session, IdleStatus status)
throws
Exception
{
//
網絡出現空閑時進行處理,并關掉連接
session.close();
}
public
void
exceptionCaught(ProtocolSession session, Throwable cause)
{
cause.printStackTrace();
//
處理所有Handler方法拋出的異常,和Mina架構拋出的異常,并關掉連接
session.close();
}
}
第四步:實現ProtocolProvider
import
org.apache.mina.protocol.
*
;
public
class
ServerProtocolProvider
implements
ProtocolProvider
{
private
static
final
ProtocolCodecFactory CODEC_FACTORY
=
new
SemsProtocolCodecFactory(
true
);
private
static
final
ProtocolHandler HANDLER
=
new
ServerSessionHandler();
public
ServerProtocolProvider()
{
}
public
ProtocolCodecFactory getCodecFactory()
{
return
CODEC_FACTORY;
}
public
ProtocolHandler getHandler()
{
return
HANDLER;
}
}
這樣協議層便完成了,啟動時跟IO層的差不多,不過我們還可以在IO層和協議層用兩個線程池,如下:
public
class
Server
{
//
服務器的監聽端口號
public
static
final
int
SERVER_PORT
=
8000
;
public
static
void
main(String[] args)
{
//
進行服務器的相關配置
ServiceRegistry registry
=
new
SimpleServiceRegistry();
IoProtocolAcceptor protocolAcceptor
=
(IoProtocolAcceptor) registry
.getProtocolAcceptor(TransportType.SOCKET);
ProtocolThreadPoolFilter protocolThreadPoolFilter
=
new
ProtocolThreadPoolFilter();
protocolThreadPoolFilter.setMaximumPoolSize(
10
);
protocolThreadPoolFilter.start();
protocolAcceptor.getFilterChain().addLast(
"
IoProtocolThreadPool
"
,
protocolThreadPoolFilter);
IoAcceptor ioAcceptor
=
protocolAcceptor.getIoAcceptor();
IoThreadPoolFilter ioThreadPoolFilter
=
new
IoThreadPoolFilter();
ioThreadPoolFilter.setMaximumPoolSize(
10
);
ioThreadPoolFilter.start();
ioAcceptor.getFilterChain().addLast(
"
IoThreadPool
"
,
ioThreadPoolFilter);
Service service
=
new
Service(
"
TranServer
"
, TransportType.SOCKET,
SERVER_PORT);
//
綁定了剛剛實現的ServerProtocolProvider
registry.bind(service,
new
ServerProtocolProvider());
}
整個MINA框架經常用到的就是這些了,這樣的事件觸發框架和兩層框架使用起來非常方便,不過這種異步框架還是有些非常明顯的缺陷:
第一,MINA只會為每個Session分配一個線程,也就是只能一個一個事件按順序執行,就算你在某個方法執行時產生了新的事件,比如收到新的數據,MINA也會先將該事件緩沖起來,所以你在執行某個方法時是不可能執行dataRead方法的,所以MINA框架是不會阻塞的,要想在一個邏輯方法中實現交互是實現不了的,因此要想出另外的實現方法。
第二,如果客戶端發完一個數據給服務器就想馬上得到回復,而不等整個業務邏輯執行完,也是實現不到的,因為MINA框架要將整個接收事件處理完了,再把回復信息發給客戶端。
第三,如果MINA是作為服務器端等待連接的,當客戶端正常關閉后業務邏輯也可繼續正常執行,但是如果MINA是連接服務器的客戶端,則當服務器關閉后,MINA的session也會關閉。
最后要說明的是MINA使用的線程池是用Leader
/
Followers Tread Pool實現的,默認最大支持2G的線程。當然MINA框架是開源的,用戶可以根據自己的需要改寫代碼,而其MINA的功能也是不斷可以擴展的。
以上是我使用MINA的經驗總結,其實MINA的相關文檔和例子也介紹了很多了,我這里算是一個總結吧,不過有很多地方只是我的個人見解,不一定正確,如果有不對的,希望高手可以提出。
http://riddickbryant.iteye.com/blog/564415
posted on 2011-09-05 00:40
HUIKK
閱讀(4621)
評論(0)
編輯
收藏
所屬分類:
java Net
新用戶注冊
刷新評論列表
只有注冊用戶
登錄
后才能發表評論。
網站導航:
博客園
IT新聞
Chat2DB
C++博客
博問
管理
相關文章:
TCP一點東東
(轉)MINA2 之IoBuffer
(轉)Mina 框架總結
socketPool
apache mina框架小試
jboss netty 框架小試
java 簡單socket 通信
[轉]JAVA-用HttpClient來模擬瀏覽器GET,POST
UDP
java 得到本機所有ip
Powered by:
BlogJava
Copyright © HUIKK
主站蜘蛛池模板:
绥阳县
|
龙江县
|
铅山县
|
安阳市
|
华阴市
|
苏州市
|
岚皋县
|
探索
|
如皋市
|
太保市
|
莱西市
|
格尔木市
|
通山县
|
翁源县
|
安宁市
|
肇庆市
|
丹江口市
|
淳化县
|
郸城县
|
金沙县
|
旺苍县
|
偃师市
|
监利县
|
梅河口市
|
仁布县
|
怀化市
|
曲沃县
|
南郑县
|
通许县
|
伊通
|
阳春市
|
卢龙县
|
汉阴县
|
衢州市
|
资中县
|
阿克陶县
|
盐城市
|
禹州市
|
东至县
|
铜山县
|
保德县
|