一、應用層和傳輸層
以http協(xié)議為例,我們在訪問一個網站時,瀏覽器會通過TCP協(xié)議發(fā)送如下字符串到服務器的應用層:
GET /test/abtest HTTP/1.1
Host: 127.0.0.1
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: PHPSESSID=970260278652571648
程序調試截圖(tio的HttpRequest.toString())

這些字符串就是應用層數據,應用層數據是按照一定格式來組織的,這個格式就是應用層協(xié)議,譬如http協(xié)議。
傳輸層在往應用層傳遞數據時,并不保證每次傳遞的數據是一個完整的應用層數據包(以http協(xié)議為例,就是并不保證應用層收到的數據剛好可以組成一個http包),這就是我們經常提到的半包和粘包。傳輸層只負責傳遞byte[]數據,應用層需要自己對byte[]數據進行解碼,以http協(xié)議為例,就是把byte[]解碼成http協(xié)議格式的字符串。
具體請參考:https://www.tiocloud.com/doc/tio/80
二、ByteBuffer
引言
ByteBuffer是nio/aio編程所必須掌握的一個數據結構,也是掌握tio所必須要學會的基礎知識。
設想你不懂Map,不懂List,不懂Set,那么你在編程領域將會一事無成,同樣的道理,如果你不懂ByteBuffer,你無法在nio/aio編程領域立足
初識ByteBuffer
我們可以把bytebuffer理解成如下幾個屬性組成的一個數據結構
byte[] bytes: 用來存儲數據
int capacity: 用來表示bytes的容量,那么可以想像capacity就等于bytes.size(),此值在初始化bytes后,是不可變的。
int limit: 用來表示bytes實際裝了多少數據,可以容易想像得到limit <= capacity,此值是可靈活變動的
int position: 用來表示在哪個位置開始往bytes寫數據或是讀數據,此值是可靈活變動的
一圖感知一下ByteBuffer

具體請參考:https://www.tiocloud.com/doc/tio/83
創(chuàng)建ByteBuffer
ByteBuffer.allocate(int cap)即可創(chuàng)建一個指定容器大小的ByteBuffer,見圖

往ByteBuffer中寫入數據
調用ByteBuffer.put(byte b)即可ByteBuffer中寫入一個字節(jié),見圖

從ByteBuffer讀取數據
對于剛剛寫好的bytebuffer,我們要讀取它的內容,需要先設置一下position和limit,否則讀的位置就不對

接下來調用ByteBuffer.get()即可讀取一個字節(jié),在讀取數據的同時,ByteBuffer的position也會跟關位移,見圖

三、半包和粘包:正確斷句才能溝通
半包
顧名思義,就是收到了半個包,這個時候不足以組成一個應用層的包。就像你要對你喜歡的人說“我喜歡你”,但是因為喝水咽著了,第一次只說了“我”字,第二次說了個“喜”字,第三個次了個“歡你”,那么就發(fā)生了半包問題,對方只有等待你說完這4個字后才知道你是想說“我喜歡你”!
用http協(xié)議為例,展示半包場景

粘包
粘包與半包相反,就是把多個想說的話,一口氣說完了,對方反應不過來,得把你的話拆開一條一條地理解
用http協(xié)議為例,展示粘包場景

說明:http協(xié)議是一來一回的,所以正常場景是不會有粘包的,但pipeline模式下是允許一方連續(xù)發(fā)多個請求的,所以會有粘包產生
為何坑人無數
初涉網絡編程的同學,往往認為每次收到的數據剛好是一個完整的數據包
于是當網絡不好,或是消息包過大時,半包的情況就發(fā)生了,而程序并沒有考慮到半包的情況,結果就是解碼失敗,導致消息丟失
當通信的對方把多條業(yè)務數據包放在一個TCP包中發(fā)過來時,粘包就產生了,而程序沒有考慮到一次TCP收包會收到多個業(yè)務包,從而解析到第一個業(yè)務包后把后面的業(yè)務包丟棄了
百度一下半包粘包,一定會搜到很多記錄,這也證明這倆貨確實坑人無數,所以看完本節(jié)內容,你還會繼續(xù)犯半包粘包的錯嗎?
具體請參考:https://www.tiocloud.com/doc/tio/84