Socket粘包問題

2021-04-28 15:22:41 字數 2702 閱讀 5926

這兩天看csdn有一些關於socket粘包,socket緩衝區設定的問題,發現自己不是很清楚,所以查資料了解記錄一下:

一兩個簡單概念長連線與短連線:

1.長連線

client方與server方先建立通訊連線,連線建立後不斷開, 然後再進行報文傳送和接收。

2.短連線

client方與server每進行一次報文收發交易時才進行通訊連線,交易完畢後立即斷開連線。此種方式常用於一點對多點

通訊,比如多個client連線乙個server.

二 什麼時候需要考慮粘包問題?

1:如果利用tcp每次傳送資料,就與對方建立連線,然後雙方傳送完一段資料後,就關閉連線,這樣就不會出現粘包問題(因為只有一種包結構,類似於http協議)。關閉連線主要要雙方都傳送close連線(參考tcp關閉協議)。如:a需要傳送一段字串給b,那麼a與b建立連線,然後傳送雙方都預設好的協議字元如"hello give me sth abour yourself",然後b收到報文後,就將緩衝區資料接收,然後關閉連線,這樣粘包問題不用考慮到,因為大家都知道是傳送一段字元。

2:如果傳送資料無結構,如檔案傳輸,這樣傳送方只管傳送,接收方只管接收儲存就ok,也不用考慮粘包

3:如果雙方建立連線,需要在連線後一段時間內傳送不同結構資料,如連線後,有好幾種結構:

1)"hello give me sth abour yourself"

2)"don't give me sth abour yourself"

那這樣的話,如果傳送方連續傳送這個兩個包出去,接收方一次接收可能會是"hello give me sth abour yourselfdon't give me sth abour yourself" 這樣接收方就傻了,到底是要幹嘛?不知道,因為協議沒有規定這麼詭異的字串,所以要處理把它分包,怎麼分也需要雙方組織乙個比較好的包結構,所以一般可能會在頭加乙個資料長度之類的包,以確保接收。

三 粘包出現原因:在流傳輸中出現,udp不會出現粘包,因為它有訊息邊界(參考windows 網路程式設計)

1 傳送端需要等緩衝區滿才傳送出去,造成粘包

2 接收方不及時接收緩衝區的包,造成多個包接收

解決辦法:

為了避免粘包現象,可採取以下幾種措施。一是對於傳送方引起的粘包現象,使用者可通過程式設計設定來避免,tcp提供了強制資料立即傳送的操作指令push,tcp軟體收到該操作指令後,就立即將本段資料傳送出去,而不必等待傳送緩衝區滿;二是對於接收方引起的粘包,則可通過優化程式設計、精簡接收程序工作量、提高接收程序優先順序等措施,使其及時接收資料,從而盡量避免出現粘包現象;三是由接收方控制,將一包資料按結構字段,人為控制分多次接收,然後合併,通過這種手段來避免粘包。

以上提到的三種措施,都有其不足之處。第一種程式設計設定方法雖然可以避免傳送方引起的粘包,但它關閉了優化演算法,降低了網路傳送效率,影響應用程式的效能,一般不建議使用。第二種方法只能減少出現粘包的可能性,但並不能完全避免粘包,當傳送頻率較高時,或由於網路突發可能使某個時間段資料報到達接收方較快,接收方還是有可能來不及接收,從而導致粘包。第三種方法雖然避免了粘包,但應用程式的效率較低,對實時應用的場合不適合。

乙個包沒有固定長度,乙太網限制在46-1500位元組,1500就是乙太網的mtu,超過這個量,tcp會為ip資料報設定偏移量進行分片傳輸,現在一般可允許應用層設定8k(ntfs系)的緩衝區,8k的資料由底層分片,而應用看來只是一次傳送。windows的緩衝區經驗值是4k,socket本身分為兩種,流(tcp)和資料報(udp),你的問題針對這兩種不同使用而結論不一

樣。甚至還和你是用阻塞、還是非阻塞socket來程式設計有關。

1、通訊長度,這個是你自己決定的,沒有系統強迫你要發多大的包,實際應該根據需求和網路狀況來決定。對於tcp,這個長度可以大點,但要知道,socket內部預設的收發緩衝區大小大概是8k,你可以用setsockopt來改變。但對於udp,就不要太大,一般在1024至10k。注意一點,你無論發多大的包,ip層和鏈路層都會把你的包進行分片傳送,一般區域網就是1500左右,廣域網就只有幾十位元組。分片後的包將經過不同的路由到達接收方,對於udp而言,要是其中乙個分片丟失,那麼接收方的ip層將把整個傳送包丟棄,這就形成丟包。顯然,要是乙個udp發包佷大,它被分片後,鏈路層丟失分片的機率就佷大,你這個udp包,就佷容易丟失,但是太小又影響效率。最好可以配置這個值,以根據不同的環境來調整到最佳狀態。

send()函式返回了實際傳送的長度,在網路不斷的情況下,它絕不會返回(傳送失敗的)錯誤,最多就是返回0。對於tcp你可以位元組寫乙個迴圈傳送。當send函式返回socket_error時,才標誌著有錯誤。但對於udp,你不要寫迴圈傳送,否則將給你的接收帶來極大的麻煩。所以udp需要用setsockopt來改變socket內部buffer的大小,以能容納你的發包。明確一點,tcp作為流,發包是不會整包到達的,而是源源不斷的到,那接收方就必須組包。而udp作為訊息或資料報,它一定是整包到達接收方。

2、關於接收,一般的發包都有包邊界,首要的就是你這個包的長度要讓接收方知道,於是就有個包頭資訊,對於tcp,接收方先收這個包頭資訊,然後再收包資料。一次收齊整個包也可以,可要對結果是否收齊進行驗證。這也就完成了組包過程。udp,那你只能整包接收了。要是你提供的接收buffer過小,tcp將返回實際接收的長度,餘下的還可以收,而udp不同的是,餘下的資料被丟棄並返回wsaemsgsize錯誤。注意tcp,要是你提供的buffer佷大,那麼可能收到的就是多個發包,你必須分離它們,還有就是當buffer太小,而一次收不完socket內部的資料,那麼socket接收事件(onreceive),可能不會再觸發,使用事件方式進行接收時,密切注意這點。這些特性就是體現了流和資料報的區別。

Socket粘包問題

這兩天看csdn有一些關於socket粘包,socket緩衝區設定的問題,發現自己不是很清楚,所以查資料了解記錄一下 一兩個簡單概念長連線與短連線 1.長連線 client方與server方先建立通訊連線,連線建立後不斷開,然後再進行報文傳送和接收。2.短連線 client方與server每進行一次...

socket粘包問題

一兩個簡單概念長連線與短連線 1.長連線 client方與server方先建立通訊連線,連線建立後不斷開,然後再進行報文傳送和接收。2.短連線 client方與server每進行一次報文收發交易時才進行通訊連線,交易完畢後立即斷開連線。此種方式常用於一點對多點 通訊,比如多個client連線乙個se...

Socket粘包問題的處理

當前在網路傳輸應用中,廣泛採用的是tcp ip通訊協議及其標準的socket應用開發程式設計介面 api tcp ip傳輸層有兩個並列的協議 tcp和udp。其中tcp transport control protocol,傳輸控制協議 是面向連線的,提供高可靠性服務。udp user datagr...