閱讀113 返回首頁    go 阿裏雲 go 技術社區[雲棲]


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

  上一篇:go 如何優雅的ALTER被引用的TABLE
  下一篇:go 觸摸雲端編程之道——基於函數計算的serverless應用開發