參考:
workerman (框架協議源碼)
https://blog.csdn.net/msdnwolaile/article/details/50769708 (tcp粘包問題經典分析)
https://wiki.swoole.com/#/learn?id=tcp粘包問題 (swoole文檔)
https://www.cnblogs.com/vipstone/p/14239160.html(粘包分包問題解決的3種思路)
粘包與拆包的概念
TCP是基於字節流的,只維護發送出去多少,確認了多少,並沒有維護消息與消息之間的邊界;
在TCP/IP協議中,由於傳輸層並不了解應用層數據的含義,發送端傳輸層可能會對應用層數據進行拆分或者合並,在接收端也同樣如此。由此而產生的問題就是常常會聽說的“粘包與拆包”的問題。
“粘包拆包”的問題在“短報文”和“一問一答”的場景下其實並不會出現。短報文是指報文長度遠小於MSS的情況,應用層的報文在TCP報文中完全可以放下。
另一方面,“一問一答”的通信模式可以保證報文會以單一的TCP包發送出去。在這兩個條件下都滿足時,我們不需要考慮“粘包拆包”問題。
反之,如果這兩個條件不同時滿足,就很可能會出現“粘包拆包”問題。
粘包的主要原因:
- 發送方每次寫入數據 < 套接字(Socket)緩沖區大小;
- 接收方讀取套接字(Socket)緩沖區數據不夠及時。
半包的主要原因:
- 發送方每次寫入數據 > 套接字(Socket)緩沖區大小;
- 發送的數據大於協議的 MTU (Maximum Transmission Unit,最大傳輸單元),因此必須拆包。
問題描述,上圖
解決方法有三種,具體如下:
1,發送端給每個數據包添加包首部,首部長度應該至少包含數據包的長度 ;
2,固定每次發送的報文長度,不夠用0補充;
3,約定好包的邊界,添加首部尾部標識,如特許字符;
關鍵方法
1,封包方法
2,解包方法
3,重要函數和字符
pack(format,arg):將參數打包成二進制字符串
unpack(format,arg):從二進制解析出字符串
ord() 返回字符的ASCII碼值
chr() ASCII碼值對應的字符,與ord互補
strlen:字符串長度 substr:從某個位置開始截取 strpos:特殊邊界字符判斷 trim/rtrim/ltrim:去除特殊邊界字符