項目須要使用Netty和DTU(無線數據傳輸模塊)通訊,須要接入多種類型的DTU,每種dtu鏈接上來以後都首先會發送一個註冊報文。須要解析該註冊報文來實現:
1. 分辨出是哪一種類型的dtu;
2. 從註冊報文中識別出注冊碼,以便決定該dtu下面鏈接的是哪一個裝置。
問題在於這是兩個不一樣廠家的DTU,他們的註冊報文的內容和長度都不相同。此時咱們就沒法使用諸如DelimitedBasedFrameDecoder、FixedLengthFrameDecoder這樣現成的工具類來解決粘包的問題,須要本身去解析收到的每一個字節,而後分別是判斷對應的報文是哪一種DTU的註冊報文,把不一樣種類的註冊包解析成內部消息。
public class DtuLoginMessage {
public enum DtuType{
dtJingfuyuan,
dtTopIot
}
private DtuType dtuType;
private String regCode;
public DtuType getDtuType() {
return dtuType;
}
public String getRegCode() {
return regCode;
}
public DtuLoginMessage(DtuType type, String regCode){
this.dtuType = type;
this.regCode = regCode;
}
}
既然沒法沒法使用工具類來解決粘包、拆包的問題,那就須要本身去解析每一個字節,那就要自定義一個ChannelHandler子類來說隨機收到的ByteBuf轉換爲DtuLoginMessage,咱們通常寫ChannelHandler都是直接繼承自ChannelInboundHandlerAdapter,而後去override他的channelRead方法,若是直接用這個類也不是不行,可是那就意味着本身要定義一個緩衝區來接受每次channelRead傳遞過來的字節,每次有新的字節過來,就要先寫入到緩衝區,而後再去檢查一下當前緩衝區的這些數據是否已是某個dtu的註冊包了,若是是的話就能夠日後走了。這裏存在的主要問題是要本身去維護這個緩衝區,若是有什麼工具類能夠幫咱們維護就更好了,記得曾經在哪裏看過。
沒錯,ByteToMessageDecoder就是幹這活的,可讓本身的Handler繼承ByteToMessageDecoder,而後重寫其中的decode方法,該方法的簽名以下,實例代碼以下:
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
DtuLoginMessage loginMsg = DtuLoginHandlerContainer.getInstance().decode(in);
if (loginMsg != null)
out.add(loginMsg);
}
每次decode被調用,都去檢查一下是不是某個dtu的註冊包,若是是,就添加到out中;若是不是,那就什麼都不用管,這樣下次decode被調用的時候還會包含以前全部沒有被解析的字節內容。