在netty開發過程中我遇到過長的消息被分割成多個小消息的問題。如下圖所示:
其實這兩條消息應該是一條消息,它們兩個才是一個完整的json字符串。查看代碼原來是客戶端與服務器端都沒有考慮TCP粘包與拆包機制。業界主流的解決方案包括:
(1)消息定長,例如每個報文的大小固定為200字節,如果不夠,空位補空格;
(2)在包尾增加回車進行分割,如FTP協議;
(3)將消息分為消息頭和消息體,消息頭包含消息的總長度;
(4)更復雜的應用層協議
慶幸的是netty提供了多種解碼器用於處理半包問題,開發人員只需要掌握這些類庫的使用就很容易處理TCP粘包與半包問題了。下面介紹一下netty常用的解碼器:
(1) LineBasedFrameDecoder解碼器
LineBasedFrameDecoder是回車換行解碼器,如果用戶發送的消息以回車換行符作為消息結束的標識,則可以直接使用Netty的LineBasedFrameDecoder對消息進行解碼,只需要在初始化Netty服務端或者客戶端時將LineBasedFrameDecoder正確的添加到ChannelPipeline中即可,不需要自己重新實現一套換行解碼器。
LineBasedFrameDecoder的工作原理是它依次遍歷ByteBuf中的可讀字節,判斷看是否有“\n”或者“\r\n”,如果有,就以此位置為結束位置,從可讀索引到結束位置區間的字節就組成了一行。它是以換行符為結束標志的解碼器,支持攜帶結束符或者不攜帶結束符兩種解碼方式,同時支持配置單行的最大長度。如果連續讀取到最大長度后仍然沒有發現換行符,就會拋出異常,同時忽略掉之前讀到的異常碼流。防止由於數據報沒有攜帶換行符導致接收到ByteBuf無限制積壓,引起系統內存溢出。
(2)DelimiterBasedFrameDecoder
DelimiterBasedFrameDecoder是分隔符解碼器,用戶可以指定消息結束的分隔符,它可以自動完成以分隔符作為碼流結束標識的消息的解碼。回車換行解碼器實際上是一種特殊的DelimiterBasedFrameDecoder解碼器。
(3)FixedLengthFrameDecoder解碼器
FixedLengthFrameDecoder是固定長度解碼器,它能夠按照指定的長度對消息進行自動解碼,開發者不需要考慮TCP的粘包/拆包等問題,非常實用。對於定長消息,如果消息實際長度小於定長,則往往會進行補位操作,它在一定程度上導致了空間和資源的浪費。但是它的優點也是非常明顯的,編解碼比較簡單,因此在實際項目中仍然有一定的應用場景。
(4)LengthFieldBasedFrameDecoder解碼器