NIO框架之MINA原始碼解析(五):NIO超級陷阱和使用同步IO與MINA通訊
NIO框架之MINA原始碼解析(一):背景
NIO框架之MINA原始碼解析(二):mina核心引擎
NIO框架之MINA原始碼解析(三):底層通訊與責任鏈模式應用
NIO框架之MINA原始碼解析(四):粘包與斷包處理及編碼與解碼
1、NIO超級陷阱
之所以說NIO超級陷阱,就是因為我在本系列開頭的那句話,因為使用缺陷導致客戶業務系統癱瘓。當然,我對這個問題進行了很深的追蹤,包括對MINA原始碼的深入瞭解,但其實之所以會出現這個問題,它的根不是MINA的原因,而是JDK底層的問題。
JDK底層在實現nio時,為了能夠喚醒等待在io上的執行緒,在windows平臺使用了兩個埠建立連線發訊息實現。看如下程式碼:
public class NIOTest {
@Test
public void test1(){
final int MAXSIZE=1000;
Selector [] sels = new Selector[ MAXSIZE];
try{
for( int i = 0 ;i< MAXSIZE ;++i ) {
sels[i] = Selector.open();
Thread.sleep(1000*10);
}
}catch( Exception ex ){
ex.printStackTrace();
}
}
}
也就是說每呼叫一次Selector.open(),就會佔用兩個隨機可用埠,相互通訊--這就是問題的根源。
當然對於我們的專案來說,這個問題的解決需要分兩步,首先限制埠數到使用者可接受範圍內,這個比較容易,我們可用只呼叫一次Selector.open()方法即可,使用單利模式;第二步,因為Selector.open()方法每次都是使用的系統當前可用的隨機埠,所以就有可能導致佔用客戶業務埠的情況,因此我們必須把Selector.open()所開的埠限制在一定範圍內,最好可以通過程式碼指定使用哪幾個埠,但是直到現在我們都沒有找到,如果親們有方法的話,很感謝能夠告訴我....,。
Selector總結如下:
Windows下,Selector.open()會自己和自己建立兩條TCP連結。不但消耗了兩個TCP連線和埠,同時也消耗了檔案描述符。
Linux下,Selector.open()會自己和自己建兩條管道。同樣消耗了兩個系統的檔案描述符。
來源於:http://blog.csdn.net/haoel/article/details/2224055
所以,現在我們現在就乾脆用傳統IO與MINA server通訊吧。
2、使用同步IO與MINA通訊
其實非常簡單,唯一的難點就在於使用同步IO與MINA通訊時,怎麼編碼和解碼,還是看下面程式碼吧。
server 端(用的MINA)
/**
* 初始化設定,啟動服務
*/
public void startServer() {
logger.debug("mina server start");
int port = SysEvnVar.managerPort;
logger.debug("manager埠號:" + port);
IoAcceptor acceptor = new NioSocketAcceptor();
/** 日誌設定 */
acceptor.getFilterChain().addLast("logger", new LoggingFilter());
//編碼與解碼工廠,使用的技術就是JDK提供的ObjectOutStream
ObjectSerializationCodecFactory objsCodec=new ObjectSerializationCodecFactory();
objsCodec.setDecoderMaxObjectSize(DEFAULTDECODER);
objsCodec.setEncoderMaxObjectSize(DEFAULTDECODER);
/** 資料轉換,編碼設定 */
acceptor.getFilterChain().addLast(
"codec",
new ProtocolCodecFilter(objsCodec));
/** 設定業務處理類 */
acceptor.setHandler(serverHandler);
/** 設定buffer容量 */
acceptor.getSessionConfig().setReadBufferSize(DEFAULTBUFFERSIZE);
/** 設定空閒時間 */
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, DEFAULTIDLETIME);
try {
/** 繫結埠 */
acceptor.bind(new InetSocketAddress(port));
logger.info("mina server bind port ("+port+") sucess");
} catch (IOException e) {
logger.error("mina server bind port ("+port+") fail:" + e.getMessage(),e);
}
}
client端(使用同步IO)
public void sendMessageToManager(HyRequest request) {
Socket socket = null;
BufferedInputStream inBuff = null;
OutputStream outBuff = null;
try {
Integer port = Integer.parseInt(hyGlobalConfigureCacheImpl.get(
"managerPort").toString());
String host = hyGlobalConfigureCacheImpl.get("managerIp")
.toString();
socket = new Socket(host, port);
inBuff = new BufferedInputStream(new DataInputStream(
socket.getInputStream()));
outBuff = socket.getOutputStream();
String json = HyJsonUtil.reqeustToJsonStr(request);
//編碼開始,使MINA能夠解析
IoBuffer buf = IoBuffer.allocate(64);
buf.setAutoExpand(true);
buf.putObject(json);
buf.flip();
byte[] bytes =new byte[buf.limit()];
buf.get(bytes);
//編碼結束,直接輸出到客戶端
outBuff.write(bytes);
outBuff.flush();
if(request.getOperation() != null && !"quit".equals(request.getOperation())){
String allreadstr = new String();
byte[] b = new byte[512 * 1024];
int len;
byte[] tmp = new byte[0];
if ((len = inBuff.read(b)) != -1) {
tmp = new byte[len];
System.arraycopy(b, 0, tmp, 0, len);
}
loger.debug("len:"+len);
//解碼開始,byte[]為MINA傳過來的資料
IoBuffer in = IoBuffer.wrap(tmp);
Object obj = null;
try {
loger.debug("in:"+in);
obj = in.getObject();
//解碼結束
loger.debug("parse success");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
loger.debug("go to exception");
loger.warn("nio parse exception",e);
obj = "exception";
}
allreadstr = (String) obj;
loger.info("receive message from "
+ socket.getRemoteSocketAddress().toString() + ",message:"
+ allreadstr);
// 請求訊息轉換為HyResponse物件
HyResponse response = HyJsonUtil.getHyResponse(allreadstr);
HyRequest hyrequest = new HyRequest();
hyResponseDispatcher = hyClientHandler.getHyResponseDispatcher();
hyResponseDispatcher.responseProcess(hyrequest, response);
if (hyrequest.getOperation() != null) {
sendMessageToManager2(hyrequest);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(null != outBuff)
outBuff.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
if(null != inBuff)
inBuff.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
}
}
}
}
看程式碼裡面的註釋,怎麼編碼和解碼,其實我是直接看MINA原始碼,把MINA的編碼和解碼方法工具類直接拷到了我們的client端,這樣就輕鬆的實現使用同步IO和MINA進行通訊。
相關文章
- NIO框架之MINA原始碼解析(二):mina核心引擎框架原始碼
- NIO框架之MINA原始碼解析(一):背景框架原始碼
- NIO框架之MINA原始碼解析(三):底層通訊與責任鏈模式應用框架原始碼模式
- NIO框架之MINA原始碼解析(四):粘包與斷包處理及編碼與解碼框架原始碼
- Java NIO框架Mina、Netty、Grizzly介紹與對比Java框架Netty
- mina2原始碼解析原始碼
- IO通訊模型(二)同步非阻塞模式NIO(NonBlocking IO)模型模式BloC
- NIO框架入門(三):iOS與MINA2、Netty4的跨平臺UDP雙向通訊實戰框架iOSNettyUDP
- mina框架框架
- Java IO之NIOJava
- Java IO 和 NIOJava
- mina 框架java服務端的搭建和通訊。框架Java服務端
- 【NIO系列】——之IO模型模型
- Java Nio通訊Java
- NIO與IO區別
- NIO和傳統IO
- Android之Mina框架學習Android框架
- 五種I/O模型和Java NIO原始碼分析模型Java原始碼
- 關於 mina netty activiemq RabbitMq nio 的比較 區別 應用NettyMQ
- Java NIO學習系列四:NIO和IO對比Java
- 使用mina解析http協議的使用HTTP協議
- Java基礎(Socket通訊和NIO)Java
- 通訊框架 t-io 學習——websocket 部分原始碼解析框架Web原始碼
- Java - Apache Mina 自定義協議通訊JavaApache協議
- 如何解讀 Java IO、NIO 中的同步阻塞與同步非阻塞?Java
- BIO到NIO原始碼的一些事兒之NIO 中原始碼
- BIO到NIO原始碼的一些事兒之NIO 上原始碼
- Java面試必問通訊框架NIO,原理詳解Java面試框架
- BIO到NIO原始碼的一些事兒之NIO 下 之 Selector原始碼
- 【NIO】Java NIO之通道Java
- Java IO學習筆記五:BIO到NIOJava筆記
- 【網路IO系列】IO的五種模型,BIO、NIO、AIO、IO多路複用、 訊號驅動IO模型AI
- 【NIO】Java NIO之緩衝Java
- Java網路程式設計和NIO詳解5:Java 非阻塞 IO 和非同步 IOJava程式設計非同步
- Java NIO通訊框架在電信領域的實踐Java框架
- 漫遊ZooKeeper nio通訊過程
- 【NIO】Java NIO之選擇器Java
- 不學無數——Java中IO和NIOJava