socket關於資料邊界的說明

2021-07-25 04:39:57 字數 1479 閱讀 8105

socket的send,recv的長度問題:

乙個包沒有固定長度,乙太網限制在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),可能不會再觸發,使用事件方式進行接收時,密切注意這點。這些特性就是體現了流和資料報的區別。

補充一點,接收buffsize >= 傳送buffsize >= 實際傳送size,對於內外部的buffer都適用,上面講的主要是socket內部的buffer大小關係。

3、tcp是有多少就收多少,如果沒有當然阻塞socket的recv就會等,直到有資料,非阻塞socket不好等,而是返回wsaewouldblock。udp,如果沒有資料,阻塞socket就會等,非阻塞socket也返回wsaewouldblock。如果有資料,它是會等整個發包到齊,並接收到整個發包,才返回。

關於socket資料長度

乙個包沒有固定長度,乙太網限制在46 1500位元組,1500就是乙太網的mtu,超過這個量,tcp會為ip資料報設定偏移量進行分片傳輸,現在一般可允許應用層設定8k ntfs系統 的緩衝區,8k的資料由底層分片,而應用層看來只是一次傳送。socket本身分為兩種,流 tcp 和資料報 udp tc...

關於邊界值的問題

今天在做練習的時候發現了乙個經常遇到的問題,邊界值的處理。我將乙個檔案中的英語文章讀入了乙個檔案流裡,然後把他儲存到了字元陣列裡面,並將每個單詞單獨存放到vector裡面。因為存在陣列裡的資料是讀取一行的資料,所以需要把其轉換為單獨的單詞。我的方法是遇到空格之後將其前面的字元都拷貝到乙個string...

請教 關於socket的資料同步問題

我現在要寫乙個telnet server 現在的情況時字串能互動,但不同步 打個比方 客戶端telnet windows自帶 連上後假設輸入了 abcdefa退格g之後回車 服務端用streamreader.readline 可以得到的是abcdefa b g我可以通過字串操作得到想要的字串.但做刪...