Netty入門(六)Decoder(解碼器)
阿新 • • 發佈:2018-05-12
err 器) repl 方法 pub HA override 異常 oid
Netty 提供了豐富的解碼器抽象基類,主要分為兩類:
- 解碼字節到消息(ByteToMessageDecoder 和 ReplayingDecoder)
- 解碼消息到消息(MessageToMessageDecoder)
一、ByteToMessageDecoder
ByteToMessageDecoder 用於將字節轉為信息(或其他字節序列)。方法如下:
在下面的例子中,我們將實現從入站 ByteBuf 讀取每個整數並將其傳遞給 pipeline 中的下一個 ChannalInboundHandler。流程如下:
代碼如下:
1 /** 2 * 讀取四字節,解碼成整形3 * 繼承於 ByteToMessageDecoder 4 * 5 */ 6 public class ToIntegerDecoder extends ByteToMessageDecoder { 7 8 @Override 9 protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { 10 if(in.readableBytes() >= 4) { // int是4字節 11out.add(in.readInt()); // 添加到解碼信息的List中 12 } 13 } 14 15 }
註意,一旦一個消息被編碼或解碼會自動調用 ReferenceCountUtil.release(message)。如果你稍後還需要用到這個引用,你可以調用 ReferenceCountUtil.retain(message)。
二、ReplayingDecoder
上面的例子讀取緩沖區的數據之前需要檢查緩沖區是否有足夠的字節,使用 ReplayingDecoder 就無需自己檢查。若 ByteBuf 中有足夠的字節,則會正常讀取;若沒有足夠的字節則會停止解碼。如下:
1 /** 2 * 讀取四字節,解碼成整形 3 * 繼承於ReplayingDecoder,不需要檢查緩存區是否有足夠的字節 4 * 5 */ 6 public class ToIntegerDecoder2 extends ReplayingDecoder<Void> { 7 8 @Override 9 protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { 10 out.add(in.readInt()); // 讀取整形並添加到解碼信息的List中 11 } 12 13 }
三、MessageToMessageDecoder
用於從一種消息解碼為另一種消息(例如,POJO 到 POJO)。與上面類似,代碼就不貼了。
四、在解碼中處理太大的幀
Netty 是異步架構需要將緩沖區字節存在內存中,知道你能夠解碼它們。因此,你不能讓你的解碼器緩存太多的數據以免耗盡可用內存。下面為解決方案:
1 /** 2 * 在解碼時處理太大的幀 3 * 4 */ 5 public class SafeByteToMessageDecoder extends ByteToMessageDecoder { 6 private static final int MAX_FRAME_SIZE = 1024; 7 8 @Override 9 protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { 10 int readable = in.readableBytes(); 11 if(readable > MAX_FRAME_SIZE) { // 緩沖區數據過大 12 in.skipBytes(readable); // 忽略所有可讀的字節 13 // 拋出異常通知這個幀數據超長 14 throw new TooLongFrameException("幀數據超長"); 15 } 16 // TODO 數據編碼 17 } 18 19 }
這種保護很重要,尤其是當你編碼一個有可變幀大小的協議的時候。
Netty入門(六)Decoder(解碼器)