之前開發一款上位機軟件就被這個問題困擾的夠嗆,原因是因為當時我完全不知道還存在這樣的問題,直到后來用了數據監控軟件才發現了我那些參差不齊的數據包,又結合了之前在網上檢索過的文章,最終才了解到了原來還有這么一回事。
所以,這次學netty的時候特意留了個心眼,提前搜索了一下netty是否也存在粘包這類問題,答案是存在!行吧,那就研究一下怎么解決吧。以下內容來自於筆者自學以及根據個人歷史經驗總結而成,暫時沒在企業項目中處理過相關問題,不保證正確。
首先,我自定義了一個非常簡單的解碼器,其實並不具備解碼功能,目的就是為了證實我的一個猜測:
public class DecodeHandler extends ByteToMessageDecoder { @Override protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception { System.out.println(byteBuf.writerIndex()); } }
在解碼器中,輸出的是寫索引的位置。
然后,我開始嘗試觸發解碼器,發現當我不斷向byteBuf中寫入內容后,寫索引也不斷增長,我寫入兩字節,寫索引就增大2,寫入三字節,寫索引就增加3。由此,我猜測每次接收數據准備進行解碼的bytebuf都是同一個!而不是新建的bytebuf!
然后,就要根據實際情況來分析了,也就是要看數據的具體格式來分析。比如我之前遇到的那種返回值,是一個定長數組,沒有固定的開頭標識,除了依靠長度來解析我實在是想不出怎么解析。
但是,還有一種情況,數據是有開頭標識的,比如每個數據包都以0x23,0x23來作為起始值。那么可以先找到數據的起始值在哪里。
private void find(ByteBuf buf) { int count = buf.readableBytes(); for (int index = buf.readerIndex(); index < count - 2; index++) { if (buf.getByte(index) == 0x23 & buf.getByte(index + 1) == 0x23) { buf.readerIndex(index); return; } } buf.readerIndex(count - 1); }
比如可以這樣找,或者也可以根據你的實際情況選擇是否直接跳過開頭標識。
然后,確定了讀索引的位置就比較好辦了,接下來的解析方式就看數據的具體格式了,在解析之前有必要檢測一下數據長度是否完整,如果不完整,可以選擇跳過這一波解析,等待數據接收完整再解析(記得要將讀索引恢復到正確的位置)。