Tcp是個(gè)“流協(xié)議”,所謂流,就是沒有界限的一連串?dāng)?shù)據(jù),沒有界限。TCP底層不了解業(yè)務(wù)數(shù)據(jù)的含義,它會(huì)根據(jù)TCP緩沖區(qū)的實(shí)際情況進(jìn)行包的劃分,所以業(yè)務(wù)上認(rèn)為,一個(gè)完整的包可能被TCP拆分為多個(gè)包進(jìn)行發(fā)送,也可能把多個(gè)小包封裝成一個(gè)大的數(shù)據(jù)包進(jìn)行發(fā)送,這就是所謂的TCP粘包和拆包問題。
粘包/拆包問題說明

image
假設(shè)客戶端分別發(fā)送了兩個(gè)數(shù)據(jù)包,D1和D2給服務(wù)端,由于服務(wù)端一次讀取到的字節(jié)數(shù)是不確定的,故可能存在以下情況:
服務(wù)端分別收到了D1和D2,沒有粘包和拆包
服務(wù)端一次性收到了D1和D2,稱為TCP粘包
服務(wù)端兩次讀取到了兩個(gè)數(shù)據(jù)包,第一次讀到了D1的完整部分和D2的部分?jǐn)?shù)據(jù),第二次讀到了D2的剩余部分。 這稱為TCP拆包
服務(wù)端兩次讀取到兩個(gè)數(shù)據(jù)包,第一次是D1的部分,第二次是D1的剩余部分和D2的完整部分
也有可能D1和D2非常大,期間發(fā)生多次拆包。
粘包/拆包原因
- 應(yīng)用程序write寫入的字節(jié)大小大于套接口緩沖區(qū)的大小
- 進(jìn)行MSS大小的TCP分段
- 以太網(wǎng)幀的payload大于MTU進(jìn)行IP分片

image
粘包問題解決方案
由于底層無法理解上層的業(yè)務(wù)數(shù)據(jù),所以底層是無法保證數(shù)據(jù)不被拆分和重組的。只能通過設(shè)計(jì)上層的協(xié)議棧來解決,業(yè)界的方案可歸納如下:
- 消息定長(zhǎng),例如每個(gè)報(bào)文固定200字節(jié),如果不夠,空位補(bǔ)空格
- 在包尾增加回車換行符進(jìn)行分割,如FTP協(xié)議
- 將消息分為消息頭和消息體,消息頭中包含消息的長(zhǎng)度,字段等信息
- 更復(fù)雜的應(yīng)用層協(xié)議
最后
在學(xué)習(xí)Netty,這里摘抄《Netty權(quán)威指南》