Socket api接口--Send(),Recv()的长度问题
生活随笔
收集整理的這篇文章主要介紹了
Socket api接口--Send(),Recv()的长度问题
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
一個包沒有固定長度,以太網(wǎng)限制在46-1500字節(jié),1500就是以太網(wǎng)的MTU,超過這個量,TCP會為IP數(shù)據(jù)報設(shè)置偏移量進(jìn)行分片傳輸,現(xiàn)在一般可允許應(yīng)用層設(shè)置8k(NTFS系統(tǒng))的緩沖區(qū),8k的數(shù)據(jù)由底層分片,而應(yīng)用層看來只是一次發(fā)送。而
windows的緩沖區(qū)經(jīng)驗值是4k。
???????? send()函數(shù)返回了實際發(fā)送的長度,在網(wǎng)絡(luò)不斷的情況下,它絕不會返回(發(fā)送失敗的)錯誤,最多就是返回0 。對于TCP你可以寫一個循環(huán)發(fā)送。當(dāng)send函數(shù)返回SOCKET_ERROR時,才標(biāo)志著有錯誤。但對于UDP,你不要寫循環(huán)發(fā)送,否則將給你的接收帶來極大的麻煩。所以UDP需要用SetSockOpt來改變Socket內(nèi)部Buffer的大小,以能容納你的發(fā)包。明確一點(diǎn),TCP作為流,發(fā)包是不會整包到達(dá)的,而是源源不斷的到,那接收方就必須組包。而UDP作為消息或數(shù)據(jù)報,它一定是整包到達(dá)接收方。
????????2、關(guān)于接收,一般的發(fā)包都有包邊界,首要的就是你這個包的長度要讓接收方知道,于是就有個包頭信息,對于TCP,接收方先收這個包頭信息,然后再收包數(shù)據(jù)。一次收齊整個包也可以,可要對結(jié)果是否收齊進(jìn)行驗證。這也就完成了組包過程。UDP,那你只能整包接收了。要是你提供的接收Buffer過小,TCP將返回實際接收的長度,余下的還可以收,而UDP不同的是,余下的數(shù)據(jù)被丟棄并返回WSAEMSGSIZE錯誤。注意TCP,要是你提供的Buffer佷大,那么可能收到的就是多個發(fā)包,你必須分離它們,還有就是當(dāng)Buffer太小,而一次收不完Socket內(nèi)部的數(shù)據(jù),那么Socket接收事件(OnReceive),可能不會再觸發(fā),使用事件方式進(jìn)行接收時,密切注意這點(diǎn)。這些特性就是體現(xiàn)了流和數(shù)據(jù)包的區(qū)別。
????????補(bǔ)充一點(diǎn),接收BuffSize >= 發(fā)送BuffSize >= 實際發(fā)送Size,對于內(nèi)外部的Buffer都適用,上面講的主要是Socket內(nèi)部的Buffer大小關(guān)系。
????????3、TCP是有多少就收多少,如果沒有當(dāng)然阻塞Socket的recv就會等,直到有數(shù)據(jù),非阻塞Socket不好等,而是返回WSAEWOULDBLOCK。UDP,如果沒有數(shù)據(jù),阻塞Socket就會等,非阻塞Socket也返回WSAEWOULDBLOCK。如果有數(shù)據(jù),它是會等整個發(fā)包到齊,并接收到整個發(fā)包,才返回。
? ? ?
Socket本身分為兩種,流(TCP)和數(shù)據(jù)報(UDP),你的問題針對這兩種不同使用而結(jié)論不一樣。甚至還和你是用阻塞、還是非阻塞Socket來編程有關(guān)。
????????1、通信長度,這個是你自己決定的,沒有系統(tǒng)強(qiáng)迫你要發(fā)多大的包,實際應(yīng)該根據(jù)需求和網(wǎng)絡(luò)狀況來決定。對于TCP,這個長度可以大點(diǎn),但要知道,Socket內(nèi)部默認(rèn)的收發(fā)緩沖區(qū)大小大概是8K,你可以用SetSockOpt來改變。但對于UDP,就不要太大,一般在1024至10K。注意一點(diǎn),你無論發(fā)多大的包,IP層和鏈路層都會把你的包進(jìn)行分片發(fā)送,一般局域網(wǎng)就是1500左右,廣域網(wǎng)就只有幾十字節(jié)。分片后的包將經(jīng)過不同的路由到達(dá)接收方,對于UDP而言,要是其中一個分片丟失,那么接收方的IP層將把整個發(fā)送包丟棄,這就形成丟包。顯然,要是一個UDP發(fā)包佷大,它被分片后,鏈路層丟失分片的幾率就佷大,你這個UDP包,就佷容易丟失,但是太小又影響效率。最好可以配置這個值,以根據(jù)不同的環(huán)境來調(diào)整到最佳狀態(tài)。???????? send()函數(shù)返回了實際發(fā)送的長度,在網(wǎng)絡(luò)不斷的情況下,它絕不會返回(發(fā)送失敗的)錯誤,最多就是返回0 。對于TCP你可以寫一個循環(huán)發(fā)送。當(dāng)send函數(shù)返回SOCKET_ERROR時,才標(biāo)志著有錯誤。但對于UDP,你不要寫循環(huán)發(fā)送,否則將給你的接收帶來極大的麻煩。所以UDP需要用SetSockOpt來改變Socket內(nèi)部Buffer的大小,以能容納你的發(fā)包。明確一點(diǎn),TCP作為流,發(fā)包是不會整包到達(dá)的,而是源源不斷的到,那接收方就必須組包。而UDP作為消息或數(shù)據(jù)報,它一定是整包到達(dá)接收方。
????????2、關(guān)于接收,一般的發(fā)包都有包邊界,首要的就是你這個包的長度要讓接收方知道,于是就有個包頭信息,對于TCP,接收方先收這個包頭信息,然后再收包數(shù)據(jù)。一次收齊整個包也可以,可要對結(jié)果是否收齊進(jìn)行驗證。這也就完成了組包過程。UDP,那你只能整包接收了。要是你提供的接收Buffer過小,TCP將返回實際接收的長度,余下的還可以收,而UDP不同的是,余下的數(shù)據(jù)被丟棄并返回WSAEMSGSIZE錯誤。注意TCP,要是你提供的Buffer佷大,那么可能收到的就是多個發(fā)包,你必須分離它們,還有就是當(dāng)Buffer太小,而一次收不完Socket內(nèi)部的數(shù)據(jù),那么Socket接收事件(OnReceive),可能不會再觸發(fā),使用事件方式進(jìn)行接收時,密切注意這點(diǎn)。這些特性就是體現(xiàn)了流和數(shù)據(jù)包的區(qū)別。
????????補(bǔ)充一點(diǎn),接收BuffSize >= 發(fā)送BuffSize >= 實際發(fā)送Size,對于內(nèi)外部的Buffer都適用,上面講的主要是Socket內(nèi)部的Buffer大小關(guān)系。
????????3、TCP是有多少就收多少,如果沒有當(dāng)然阻塞Socket的recv就會等,直到有數(shù)據(jù),非阻塞Socket不好等,而是返回WSAEWOULDBLOCK。UDP,如果沒有數(shù)據(jù),阻塞Socket就會等,非阻塞Socket也返回WSAEWOULDBLOCK。如果有數(shù)據(jù),它是會等整個發(fā)包到齊,并接收到整個發(fā)包,才返回。
總結(jié)
以上是生活随笔為你收集整理的Socket api接口--Send(),Recv()的长度问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 餐厅扫码点餐系统源码 外卖订餐小程序源码
- 下一篇: 算法(第四版)IDEA终极环境配置