socket,如果是做tcp連接,可能會遇到粘包與半包的問題,TCP屬於傳輸層的協議,傳輸層除了有TCP協議外還有UDP協議。那么UDP是否會發生粘包或拆包的現象呢?答案是不會。UDP是基於報文發送的,從UDP的幀結構可以看出,在UDP首部采用了16bit來指示UDP數據報文的長度,因此在應用層能很好的將不同的數據報文區分開,從而避免粘包和拆包的問題。而TCP是基於字節流的,雖然應用層和TCP傳輸層之間的數據交互是大小不等的數據塊,但是TCP把這些數據塊僅僅看成一連串無結構的字節流,沒有邊界;另外從TCP的幀結構也可以看出,在TCP的首部沒有表示數據長度的字段,在使用TCP傳輸數據時,才有粘包或者拆包現象發生的可能。粘包就是多組數據被一並接收了,粘在了一起,無法做划分;半包就是有數據接收不完整,無法處理。要解決粘包、半包的問題,一般在設計數據(消息)格式時會約定好一個字段專門用於描述數據包的長度,這樣就使數據有了邊界,依靠這個邊界,就能把每組數據划分出來,數據不完整時也能獲知數據的缺失。
封包
一般在使用Socket的時候,后台會對Socket傳輸數據有一個自定義的協議,協議可能有些差別不過基本上是大同小異。
Socket發送給服務器的數據,最終要轉換成二進制流數據,並且按照協議約定的格式。
eg:消息=消息頭+消息體。消息頭用於描述消息本身的基本信息,消息體則為消息的具體內容
粘包、拆包
我們假設在主機A和主機B的應用程序之間有一條TCP連接,主機A有兩條報文D1,D2要發送到B主機,並兩次調用send來發送,每條報文調用一次。
那么,我們自然而然的希望兩條報文是作為兩個獨立的實體,在各自的分組中發送
這樣的話,我們無需做任何特別的處理,便能夠很容易的區分每一個獨立的數據,並根據需求分別做相應的處理。但現實往往是有所偏差的,實際的數據傳輸過程很可能不會遵循這個模型。而是會采用以下四種方式之一進行傳輸
實際上,可能的情況還不止4種,這里我們就不做深入了解,以上就是造成粘包的原因。
解決思路:拆包
在上面說到我們給每個數據包添加頭部,頭部中包含數據包的長度,這樣接收到數據后,通過讀取頭部的長度字段,便知道每一個數據包的實際長度了,再根據長度去讀取指定長度的數據便能獲取到正確的數據了。
再來回顧一下 協議:


完整的數據包 = 服務號 + 數據包長度 + 數據
數據包頭 = Id(4B) + length(4B) 共占用8字節
數據包 = length(假設占100個字節)
所以這條消息的長度就是108字節可以看到,要想知道一條完整數據的邊界,關鍵就是數據包頭中的length字段
iOS客戶端就需要很好的第三方CocoaAsyncSocket來進行長連接連接和傳輸數據,該第三方地 址:https://github.com/robbiehanson/CocoaAsyncSocket,
iOS開發之Socket通信實戰--Request請求數據包編碼模塊
補充博客:初用 CocoaAsyncSocket