mina 框架知識點部分整理
之前做個一段時間的遊戲開發,用到了mina通訊框架,怕久了忘記,這裏整理下知識點。第一個就是搞清楚他的核心nio,但是講這個就必須先搞清楚bio。jdk1.4之前用的是阻塞-BIO,jdk1.4之後引入NIO-非阻塞IO, jdk1.7後引入了 AIO-異步非阻塞IO。BIO相信大家入門時都寫過:
while(true){
Socket s = socket.accept();
//操作s
//new Thread(s);
//s.read();
//s.write();
}
bio編程時需要一個線程去循環檢測是否有新的socket連接進來,連接進來後socket就放入新的線程或者連接池。所以socket個數和線程個數M:N,M>N。bio是麵相流的,建立鏈接,讀取,寫入都是同步阻塞的。這就意味著對方處理數據較慢或者網絡傳輸數據較慢時,處理這個請求的線程隻有阻塞等待。就算用了線程池,也會把線程吃完,後續處理不能正常進行。nio socket編程
將通道和對應的事件會一起注冊到selector上。事件分四種:服務器接收客戶端連接,客戶端連接服務器,讀事件,寫事件。所有的事件都可以共用一個selector,也可以分開。
while(true){
int n=selector.select();
if(n>0){
//取出就緒通道
//判斷事件類型
//處理對應事件
}
}
selector選擇器也需要一個線程去輪訓是否有就緒的通道。原來程序要讀取對方傳來的數據時,需要阻塞等待對方的流數據在網卡組裝好後,才能讀取。就像你要下樓等到快遞員給你送快遞。而nio是當程序需要讀取數據時,隻需要將讀取事件和通道一起注冊到選擇器上,選擇器一直輪訓你關心的數據準備好沒有。當數據到達網卡且準備好時,就被輪訓出來。 當有就緒通道時,就把通道裏麵的數據讀到緩衝區裏麵。通道是否就緒,是由操作係統決定的。mina通訊框架的粘包和斷包問題
什麼是粘包,斷包問題?
TCP是麵相字節流的,他的消息是無邊界概念的,就好比文章沒有標點符號,沒有分段,全部粘在一起。那麼發送方發送好幾個包,接收方當作一個包一次性接收,就叫粘包。而當發送方發送的數據太大時,又不的不拆成幾個包分開發送,就叫斷包。那怎麼解決呢?
1,常見的就是用特殊分隔符分割。比如\r\n之類的。
2,還有就是把消息的長度加到消息頭部。
//封包
public void encode(IoSession session, Object message,
ProtocolEncoderOutput out) throws Exception {
Map retm = (Map) message;
//map轉字節數組
byte[] bytes = gzipMsg(retm);
//消息長度
int len = bytes.length;
IoBuffer buf = IoBuffer.allocate(len+4);
buf.setAutoExpand(true);
//把長度加消息開頭
writeInt(buf, len);
buf.put(bytes);
buf.flip();
out.write(buf);
}
//拆包
@Override
public MessageDecoderResult decodable(IoSession session, IoBuffer buf) {
return messageComplete(buf) ? MessageDecoderResult.OK
: MessageDecoderResult.NEED_DATA;
}
private boolean messageComplete(IoBuffer in) {
int remaining = in.remaining();
log.info("remaining:" + remaining);
if (remaining < 6)
return false;
//讀取消息頭
int len = readInt(in);
//看本次收到的消息完整嗎
if (len > in.remaining())
return false;
return true;//不完成就繼續接收
}
@Override
public MessageDecoderResult decode(IoSession session, IoBuffer buf,
ProtocolDecoderOutput out) throws Exception {
// Try to decode body
int length = readInt(buf);
if (length < 6)
return MessageDecoderResult.NEED_DATA;
if (length > 128 * 1024)
return MessageDecoderResult.NOT_OK;
byte[] message = new byte[length];
buf.get(message);
out.write(message);
message = null;
return MessageDecoderResult.OK;
}
未完待續...最後更新:2017-05-03 21:49:06