Netty測試異常處理

2018-08-08 10:55 更新

當出現(xiàn)入站或者出站數(shù)據(jù)傳輸不足的情況也要進行處理,例如拋出一個異常。這種情況可能是因為你輸入錯誤或者處理大的資源或者其他的異常導致的。接下來我們來寫一個實現(xiàn),一旦輸入的字節(jié)數(shù)超過了限制長度,TooLongFrameException 就會被拋出,用這樣的功能來防止資源耗盡的問題??聪聢D:

在圖10.4最大幀大小被設置為3個字節(jié)。

Figure%2010

Figure 10.4 Decoding via FrameChunkDecoder

上圖顯示幀的大小被限制為3字節(jié),若輸入的字節(jié)超過3字節(jié),則超過的字節(jié)被丟棄并拋出 TooLongFrameException。在 ChannelPipeline 中的其他ChannelHandler 實現(xiàn)可以處理 TooLongFrameException 或者忽略異常。處理異常在 ChannelHandler.exceptionCaught() 方法中完成,ChannelHandler 提供了一些具體的實現(xiàn),看下面代碼:

public class FrameChunkDecoder extends ByteToMessageDecoder {  //1

    private final int maxFrameSize;

    public FrameChunkDecoder(int maxFrameSize) {
        this.maxFrameSize = maxFrameSize;
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        int readableBytes = in.readableBytes();  //2
        if (readableBytes > maxFrameSize)  {
            // discard the bytes   //3
            in.clear();
            throw new TooLongFrameException();
        }
        ByteBuf buf = in.readBytes(readableBytes); //4
        out.add(buf);  //5
    }
}
  1. 繼承 ByteToMessageDecoder 用于解碼入站字節(jié)到消息
  2. 指定最大需要的幀產(chǎn)生的體積
  3. 如果幀太大就丟棄并拋出一個 TooLongFrameException 異常
  4. 同時從 ByteBuf 讀到新幀
  5. 添加幀到解碼消息 List

示例如下:

Listing 10.6 Testing FixedLengthFrameDecoder

public class FrameChunkDecoderTest {

    @Test    //1
    public void testFramesDecoded() {
        ByteBuf buf = Unpooled.buffer();  //2
        for (int i = 0; i < 9; i++) {
            buf.writeByte(i);
        }
        ByteBuf input = buf.duplicate();

        EmbeddedChannel channel = new EmbeddedChannel(new FrameChunkDecoder(3));  //3
        Assert.assertTrue(channel.writeInbound(input.readBytes(2)));  //4
        try {
            channel.writeInbound(input.readBytes(4)); //5
            Assert.fail();  //6
        } catch (TooLongFrameException e) {
            // expected
        }
        Assert.assertTrue(channel.writeInbound(input.readBytes(3)));  //7


        Assert.assertTrue(channel.finish());  //8

        ByteBuf read = (ByteBuf) channel.readInbound();
        Assert.assertEquals(buf.readSlice(2), read); //9
        read.release();

        read = (ByteBuf) channel.readInbound();
        Assert.assertEquals(buf.skipBytes(4).readSlice(3), read);
        read.release();

        buf.release();
    }
}
  1. 使用 @Test 注解
  2. 新建 ByteBuf 寫入 9 個字節(jié)
  3. 新建 EmbeddedChannel 并安裝一個 FixedLengthFrameDecoder 用于測試
  4. 寫入 2 個字節(jié)并預測生產(chǎn)的新幀(消息)
  5. 寫一幀大于幀的最大容量 (3) 并檢查一個 TooLongFrameException 異常
  6. 如果異常沒有被捕獲,測試將失敗。注意如果類實現(xiàn) exceptionCaught() 并且處理了異常 exception,那么這里就不會捕捉異常
  7. 寫剩余的 2 個字節(jié)預測一個幀
  8. 標記 channel 完成
  9. 讀到的產(chǎn)生的消息并且驗證值。注意 assertEquals(Object,Object)測試使用 equals() 是否相當,不是對象的引用是否相當

即使我們使用 EmbeddedChannel 和 ByteToMessageDecoder。

應該指出的是,同樣的可以做每個 ChannelHandler 的實現(xiàn),將拋出一個異常。

乍一看,這看起來很類似于測試我們寫在清單10.2中,但它有一個有趣的轉折,即 TooLongFrameException 的處理。這里使用的 try/catch 塊是 EmbeddedChannel 的一種特殊的特性。如果其中一個“write*"編寫方法產(chǎn)生一個受控異常將被包裝在一個 RuntimeException。這使得測試更加容易,如果異常處理的一部分處理。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號