Posted on 2011-09-14 12:38
火炎炎 閱讀(1809)
評論(0) 編輯 收藏
使用過mina的同學應該都遇到到過,在解碼時少包、多包的問題,查閱了很多資料還是迷迷糊糊的,經過
不懈努力,終于解決了。原來解決方法是那樣的簡單。廢話少說,請看列子。
另外建了一個交流群:19702042,大家可以在線交流
問題:我發送的是xml字符串數據,在發送數據后,接收方在解碼的時候可能接到1條,也可能是多條,還
可能是半條或一條半,解決方法就是使用CumulativeProtocolDecoder
首先,在編碼的時候要把前4位設成標志位,標志消息內容的長度。里面的重點是doDecode的返回值,一
定要繼承CumulativeProtocolDecoder 哦。
清看decode的寫法:
- public class AsResponseDecoder extends CumulativeProtocolDecoder {
- private static Logger LOG = LoggerFactory.getLogger(AsResponseDecoder.class);
- private final Charset charset;
-
- public AsResponseDecoder(Charset charset){
- this.charset = charset;
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
- public boolean doDecode(IoSession session, IoBuffer in,
- ProtocolDecoderOutput out) throws Exception {
-
- CharsetDecoder cd = charset.newDecoder();
- if(in.remaining() > 0){
- byte [] sizeBytes = new byte[4];
- in.mark();
- in.get(sizeBytes);
-
- int size = NumberUtil.byteArrayToInt(sizeBytes);
-
- if(size > in.remaining()){
- in.reset();
- return false;
- } else{
- byte[] bytes = new byte[size];
- in.get(bytes, 0, size);
- String xmlStr = new String(bytes,"UTF-8");
- System.out.println("------------"+xmlStr);
- if(null != xmlStr && xmlStr.length() > 0){
- AsResponse resCmd = new AsResponse();
- AsXmlPacker.parse(resCmd, xmlStr);
- if(resCmd != null){
- out.write(resCmd);
- }
- }
- if(in.remaining() > 0){
-
- 一次,進行下一次解析
- return true;
- }
- }
- }
- return false;
- }
-
-
- }
下面附上Encode類
- public class AsResponseEncoder extends ProtocolEncoderAdapter {
- private final Charset charset;
-
- public AsResponseEncoder(Charset charset){
- this.charset = charset;
- }
-
- public void encode(IoSession session, Object message,
- ProtocolEncoderOutput out) throws Exception {
- CharsetEncoder ce = charset.newEncoder();
- IoBuffer buffer = IoBuffer.allocate(100).setAutoExpand(true);
-
- AsResponse respCmd = (AsResponse) message;
-
- String xml = AsXmlPacker.pack(respCmd);
- byte[] bytes = xml.getBytes();
- byte[] sizeBytes = NumberUtil.intToByteArray(bytes.length);
-
- buffer.put(sizeBytes);
- buffer.put(bytes);
- buffer.flip();
- out.write(buffer);
- }
-
-
- }
JDK ByteBuffer
屬性:
Mark |
上次position的快照 |
Position |
當前讀寫索引未知 |
Limit |
緩沖區限制 |
Capacity |
緩沖區能力 |
Offset |
偏移量 |
說明:
- Position(Mark)<=limit<=capacity
- 當position==limit時就沒有字節可讀寫了
- 每次get或put都將增加position
- 重置mark就是設置mark=-1
方法:
Limit(int) |
如果position>limit, position = limit,如果mark>limit, 重置mark |
Mark() |
取當前的position的快照標記mark |
Reset() |
恢復position到先前標記的mark |
Clear() |
limit=capacity , position=0,重置mark,但是不清空數據,為了從頭開始put做準備,其實就是清空數據,因為你put就覆蓋了原來的數據 |
Rewind() |
position=0,重置mark,一系列寫操作后,為了從頭開始get做準備,和clear()有用途上的區別,他大部分是用來從頭開始讀取,而clear是大部分用來重頭開始填充,就是清理的意思 |
Flip() |
limit=position , position=0,重置mask,為了將buf寫出做好準備,一般是結束buf操作,將buf寫入輸出流時調用,這個必須要調用,否則極有可能position!=limit,導致position后面沒有數據,每次寫入數據到輸出流時,必須確保position=limit。 |
Remaining() |
返回limit-position,返回緩沖器中的剩余字節 |
Wrap(byte[]) |
組裝到新的buffer,capacity=limit=byte[].length,position=0 重置mark |
Slice() |
分割緩沖器,將remaining的空間形成一個新的buffer,新的position=0,limit=capacity=remaining,重置mark,和主緩沖區內容共享,其它都獨立 |
Duplicate() |
復制緩沖區,內容共享,其它都獨立 |
asReadOnlyBuffer() |
和duplicate一樣,只是不可寫 |
Compact() |
將position和limit之間的字節移到最前面,position=limit-position,這就是這里的壓縮的意思,一般是結束buf操作,將buf寫入輸出流時調用 |
Position(int) |
position=newPosition,如果position<mark,重置mark |
Remaining() |
返回position和limit之間的字節數 |
|
JDK ByteBuffer |
Mina IoBuffer |
動態擴展capacity |
否 |
是 |
支持String讀寫 |
否 |
是 |
線程安全 |
否 |
否 |
可主動釋放緩沖區占用內存 |
否 |
是 |