精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何解決tcp通信中的粘包問題

科技綠洲 ? 來(lái)源:Linux開發(fā)架構(gòu)之路 ? 作者:Linux開發(fā)架構(gòu)之路 ? 2023-11-11 11:40 ? 次閱讀

一、 粘包問題概述

1、描述背景

采用TCP協(xié)議進(jìn)行網(wǎng)絡(luò)數(shù)據(jù)傳送的軟件設(shè)計(jì)中,普遍存在粘包問題。這主要是由于現(xiàn)代操作系統(tǒng)的網(wǎng)絡(luò)傳輸機(jī)制所產(chǎn)生的。我們知道,網(wǎng)絡(luò)通信采用的套接字(socket)技術(shù),其實(shí)現(xiàn)實(shí)際是由系統(tǒng)內(nèi)核提供一片連續(xù)緩存(流緩沖)來(lái)實(shí)現(xiàn)應(yīng)用層程序與網(wǎng)卡接口之間的中轉(zhuǎn)功能。多個(gè)數(shù)據(jù)包被連續(xù)存儲(chǔ)于連續(xù)的緩存中,在對(duì)數(shù)據(jù)包進(jìn)行讀取時(shí)由于無(wú)法確定發(fā)生方的發(fā)送邊界,而采用某一估測(cè)值大小來(lái)進(jìn)行數(shù)據(jù)讀出,若雙方的size不一致時(shí)就會(huì)使數(shù)據(jù)包的邊界發(fā)生錯(cuò)位,導(dǎo)致讀出錯(cuò)誤的數(shù)據(jù)分包,進(jìn)而曲解原始數(shù)據(jù)含義。

2、粘包的概念

粘包問題的本質(zhì)就是數(shù)據(jù)讀取邊界錯(cuò)誤所致,通過(guò)下圖可以形象地理解其現(xiàn)象。

如圖1所示,當(dāng)前的socket緩存中已經(jīng)有6個(gè)數(shù)據(jù)分組到達(dá),其大小如圖中數(shù)字。而應(yīng)用程序在對(duì)數(shù)據(jù)進(jìn)行收取時(shí)(如圖2),采用了300字節(jié)的要求去讀取,則會(huì)誤將pkg1和pkg2一起收走當(dāng)做一個(gè)包來(lái)處理。而實(shí)際上,很可能pkg1是一個(gè)文本文件的內(nèi)容,而pkg2則可能是一個(gè)音頻內(nèi)容,這風(fēng)馬牛不相及的兩個(gè)數(shù)據(jù)包卻被揉進(jìn)一個(gè)包進(jìn)行處理,顯然有失妥當(dāng)。嚴(yán)重時(shí)可能因?yàn)閬G了pkg2而導(dǎo)致軟件陷入異常分支產(chǎn)生烏龍事件。

因此,粘包問題必須引起所有軟件設(shè)計(jì)者(項(xiàng)目經(jīng)理)的高度重視!

那么,或許會(huì)有讀者發(fā)問,為何不讓接收程序按照100字節(jié)來(lái)讀取呢?我想如果您了解一些TCP編程的話就不會(huì)有這樣的問題。網(wǎng)絡(luò)通信程序中,數(shù)據(jù)包通常是不能確定大小的,尤其在軟件設(shè)計(jì)階段無(wú)法真的做到確定為一個(gè)固定值。比如聊天軟件客戶端若采用TCP傳輸一個(gè)用戶名和密碼到服務(wù)端進(jìn)行驗(yàn)證登陸,我想這個(gè)數(shù)據(jù)包不過(guò)是幾十字節(jié),至多幾百字節(jié)即可發(fā)送完畢,而有時(shí)候要傳輸一個(gè)很大的視頻文件,即使分包發(fā)送也應(yīng)該一個(gè)包在幾千字節(jié)吧。(據(jù)說(shuō),某國(guó)電信平臺(tái)的MW中見到過(guò)一次發(fā)送1.5萬(wàn)字節(jié)的電話數(shù)據(jù))這種情況下,發(fā)送數(shù)據(jù)的分包大小無(wú)法固定,接收端也就無(wú)法固定。所以一般采用一個(gè)較為合理的預(yù)估值進(jìn)行輪詢接收。(網(wǎng)卡的MTU都是1500字節(jié),因此這個(gè)預(yù)估值一般為MTU的1~3倍)。

相信讀者對(duì)粘包問題應(yīng)該有了初步認(rèn)識(shí)了。

二、粘包回避設(shè)計(jì)

設(shè)計(jì)方案一:定長(zhǎng)發(fā)送

在進(jìn)行數(shù)據(jù)發(fā)送時(shí)采用固定長(zhǎng)度的設(shè)計(jì),也就是無(wú)論多大數(shù)據(jù)發(fā)送都分包為固定長(zhǎng)度(為便于描述,此處定長(zhǎng)為記為L(zhǎng)EN),也就是發(fā)送端在發(fā)送數(shù)據(jù)時(shí)都以LEN為長(zhǎng)度進(jìn)行分包。這樣接收方都以固定的LEN進(jìn)行接收,如此一來(lái)發(fā)送和接收就能一一對(duì)應(yīng)了。分包的時(shí)候不一定能完整的恰好分成多個(gè)完整的LEN的包,最后一個(gè)包一般都會(huì)小于LEN,這時(shí)候最后一個(gè)包可以在不足的部分填充空白字節(jié)。

當(dāng)然,這種方法會(huì)有缺陷。1.最后一個(gè)包的不足長(zhǎng)度被填充為空白部分,也即無(wú)效字節(jié)序。那么接收方可能難以辨別這無(wú)效的部分,它本身就是為了補(bǔ)位的,并無(wú)實(shí)際含義。這就為接收端處理其含義帶來(lái)了麻煩。當(dāng)然也有解決辦法,可以通過(guò)增添標(biāo)志位的方法來(lái)彌補(bǔ),即在每一個(gè)數(shù)據(jù)包的最前面增加一個(gè)定長(zhǎng)的報(bào)頭,然后將該數(shù)據(jù)包的末尾標(biāo)記一并發(fā)送。接收方根據(jù)這個(gè)標(biāo)記確認(rèn)無(wú)效字節(jié)序列,從而實(shí)現(xiàn)數(shù)據(jù)的完整接收。2.在發(fā)送包長(zhǎng)度隨機(jī)分布的情況下,會(huì)造成帶寬浪費(fèi)。比如發(fā)送長(zhǎng)度可能為 1,100,1000,4000字節(jié)等等,則都需要按照定長(zhǎng)最大值即4000來(lái)發(fā)送,數(shù)據(jù)包小于4000字節(jié)的其他包也會(huì)被填充至4000,造成網(wǎng)絡(luò)負(fù)載的無(wú)效浪費(fèi)。

綜上,此方案適在發(fā)送數(shù)據(jù)包長(zhǎng)度較為穩(wěn)定(趨于某一固定值)的情況下有較好的效果。

設(shè)計(jì)方案二:尾部標(biāo)記序列

在每個(gè)要發(fā)送的數(shù)據(jù)包的尾部設(shè)置一個(gè)特殊的字節(jié)序列,此序列帶有特殊含義,跟字符串的結(jié)束符標(biāo)識(shí)”?”一樣的含義,用來(lái)標(biāo)示這個(gè)數(shù)據(jù)包的末尾,接收方可對(duì)接收的數(shù)據(jù)進(jìn)行分析,通過(guò)尾部序列確認(rèn)數(shù)據(jù)包的邊界。

這種方法的缺陷較為明顯:1.接收方需要對(duì)數(shù)據(jù)進(jìn)行分析,甄別尾部序列。2.尾部序列的確定本身是一個(gè)問題。什么樣的序列可以向”?”一樣來(lái)做一個(gè)結(jié)束符呢?這個(gè)序列必須是不具備通常任何人類或者程序可識(shí)別的帶含義的數(shù)據(jù)序列,就像“?”是一個(gè)無(wú)效字符串內(nèi)容,因而可以作為字符串的結(jié)束標(biāo)記。那普通的網(wǎng)絡(luò)通信中,這個(gè)序列是什么呢?我想一時(shí)間很難找到恰當(dāng)?shù)拇鸢浮?/p>

設(shè)計(jì)方案三:頭部標(biāo)記分步接收

這個(gè)方法是作者有限學(xué)識(shí)里最好的辦法了。它既不損失效率,還完美解決了任何大小的數(shù)據(jù)包的邊界問題。

這個(gè)方法的實(shí)現(xiàn)是這樣的,定義一個(gè)用戶報(bào)頭,在報(bào)頭中注明每次發(fā)送的數(shù)據(jù)包大小。接收方每次接收時(shí)先以報(bào)頭的size進(jìn)行數(shù)據(jù)讀取,這必然只能讀到一個(gè)報(bào)頭的數(shù)據(jù),從報(bào)頭中得到該數(shù)據(jù)包的數(shù)據(jù)大小,然后再按照此大小進(jìn)行再次讀取,就能讀到數(shù)據(jù)的內(nèi)容了。這樣一來(lái),每個(gè)數(shù)據(jù)包發(fā)送時(shí)都封裝一個(gè)報(bào)頭,然后接收方分兩次接收一個(gè)包,第一次接收?qǐng)?bào)頭,根據(jù)報(bào)頭大小第二次才接收數(shù)據(jù)內(nèi)容。(此處的data[0]的本質(zhì)是一個(gè)指針,指向數(shù)據(jù)的正文部分,也可以是一篇連續(xù)數(shù)據(jù)區(qū)的起始位置。因此可以設(shè)計(jì)成data[user_size],這樣的話。)

下面通過(guò)一個(gè)圖來(lái)展現(xiàn)設(shè)計(jì)思想。

圖片

由圖看出,數(shù)據(jù)發(fā)送多了封裝報(bào)頭的動(dòng)作;接收方將每個(gè)包的接收拆分成了兩次。

這方案看似精妙,實(shí)則也有缺陷:1.報(bào)頭雖小,但每個(gè)包都需要多封裝sizeof(_data_head)的數(shù)據(jù),積累效應(yīng)也不可完全忽略。2.接收方的接收動(dòng)作分成了兩次,也就是進(jìn)行數(shù)據(jù)讀取的操作被增加了一倍,而數(shù)據(jù)讀取操作的recv或者read都是系統(tǒng)調(diào)用,這對(duì)內(nèi)核而言的開銷是一個(gè)不能完全忽略的影響,對(duì)程序而言性能影響可忽略(系統(tǒng)調(diào)用的速度非??欤?。

優(yōu)點(diǎn):避免了程序設(shè)計(jì)的復(fù)雜性,其有效性便于驗(yàn)證,對(duì)軟件設(shè)計(jì)的穩(wěn)定性要求來(lái)說(shuō)更容易達(dá)標(biāo)。綜上,方案三乃上策!

補(bǔ)充:

什么時(shí)候需要考慮粘包問題?

1:如果利用tcp每次發(fā)送數(shù)據(jù),就與對(duì)方建立連接,然后雙方發(fā)送完一段數(shù)據(jù)后,就關(guān)閉連接,這樣就不會(huì)出現(xiàn)粘包問題(因?yàn)橹挥幸环N包結(jié)構(gòu),類似于http協(xié)議)。關(guān)閉連接主要要雙方都發(fā)送close連接(參考tcp關(guān)閉協(xié)議)。如:A需要發(fā)送一段字符串給B,那么A與B建立連接,然后發(fā)送雙方都默認(rèn)好的協(xié)議字符如"hello give me sth abour yourself",然后B收到報(bào)文后,就將緩沖區(qū)數(shù)據(jù)接收,然后關(guān)閉連接,這樣粘包問題不用考慮到,因?yàn)榇蠹叶贾朗前l(fā)送一段字符。

2:如果發(fā)送數(shù)據(jù)無(wú)結(jié)構(gòu),如文件傳輸,這樣發(fā)送方只管發(fā)送,接收方只管接收存儲(chǔ)就ok,也不用考慮粘包

3:如果雙方建立連接,需要在連接后一段時(shí)間內(nèi)發(fā)送不同結(jié)構(gòu)數(shù)據(jù),如連接后,有好幾種結(jié)構(gòu):

1)"hello give me sth abour yourself"

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

那這樣的話,如果發(fā)送方連續(xù)發(fā)送這個(gè)兩個(gè)包出去,接收方一次接收可能會(huì)是"hello give me sth abour yourselfDon't give me sth abour yourself" 這樣接收方就傻了,到底是要干嘛?不知道,因?yàn)閰f(xié)議沒有規(guī)定這么詭異的字符串,所以要處理把它分包,怎么分也需要雙方組織一個(gè)比較好的包結(jié)構(gòu),所以一般可能會(huì)在頭加一個(gè)數(shù)據(jù)長(zhǎng)度之類的包,以確保接收。

粘包出現(xiàn)原因:在流傳輸中出現(xiàn),UDP不會(huì)出現(xiàn)粘包,因?yàn)樗邢⑦吔?/p>

1 發(fā)送端需要等緩沖區(qū)滿才發(fā)送出去,造成粘包 2 接收方不及時(shí)接收緩沖區(qū)的包,造成多個(gè)包接收

解決辦法:

為了避免粘包現(xiàn)象,可采取以下幾種措施。

  • 一是對(duì)于發(fā)送方引起的粘包現(xiàn)象,用戶可通過(guò)編程設(shè)置來(lái)避免,TCP提供了強(qiáng)制數(shù)據(jù)立即傳送的操作指令push,TCP軟件收到該操作指令后,就立即將本段數(shù)據(jù)發(fā)送出去,而不必等待發(fā)送緩沖區(qū)滿;
  • 二是對(duì)于接收方引起的粘包,則可通過(guò)優(yōu)化程序設(shè)計(jì)、精簡(jiǎn)接收進(jìn)程工作量、提高接收進(jìn)程優(yōu)先級(jí)等措施,使其及時(shí)接收數(shù)據(jù),從而盡量避免出現(xiàn)粘包現(xiàn)象;
  • 三是由接收方控制,將一包數(shù)據(jù)按結(jié)構(gòu)字段,人為控制分多次接收,然后合并,通過(guò)這種手段來(lái)避免粘包。

以上提到的三種措施,都有其不足之處。第一種編程設(shè)置方法雖然可以避免發(fā)送方引起的粘包,但它關(guān)閉了優(yōu)化算法,降低了網(wǎng)絡(luò)發(fā)送效率,影響應(yīng)用程序的性能,一般不建議使用。第二種方法只能減少出現(xiàn)粘包的可能性,但并不能完全避免粘包,當(dāng)發(fā)送頻率較高時(shí),或由于網(wǎng)絡(luò)突發(fā)可能使某個(gè)時(shí)間段數(shù)據(jù)包到達(dá)接收方較快,接收方還是有可能來(lái)不及接收,從而導(dǎo)致粘包。第三種方法雖然避免了粘包,但應(yīng)用程序的效率較低,對(duì)實(shí)時(shí)應(yīng)用的場(chǎng)合不適合。

為什么基于TCP的通訊程序需要進(jìn)行封包和拆包

TCP是個(gè)"流"協(xié)議,所謂流,就是沒有界限的一串?dāng)?shù)據(jù).大家可以想想河里的流水,是連成一片的,其間是沒有分界線的.但一般通訊程序開發(fā)是需要定義一個(gè)個(gè)相互獨(dú)立的數(shù)據(jù)包的,比如用于登陸的數(shù)據(jù)包,用于注銷的數(shù)據(jù)包.由于TCP"流"的特性以及網(wǎng)絡(luò)狀況,在進(jìn)行數(shù)據(jù)傳輸時(shí)會(huì)出現(xiàn)以下幾種情況.

假設(shè)我們連續(xù)調(diào)用兩次send分別發(fā)送兩段數(shù)據(jù)data1和data2,在接收端有以下幾種接收情況(當(dāng)然不止這幾種情況,這里只列出了有代表性的情況). A.先接收到data1,然后接收到data2. B.先接收到data1的部分?jǐn)?shù)據(jù),然后接收到data1余下的部分以及data2的全部. C.先接收到了data1的全部數(shù)據(jù)和data2的部分?jǐn)?shù)據(jù),然后接收到了data2的余下的數(shù)據(jù). D.一次性接收到了data1和data2的全部數(shù)據(jù).

對(duì)于A這種情況正是我們需要的,不再做討論.對(duì)于B,C,D的情況就是大家經(jīng)常說(shuō)的"粘包",就需要我們把接收到的數(shù)據(jù)進(jìn)行拆包,拆成一個(gè)個(gè)獨(dú)立的數(shù)據(jù)包.為了拆包就必須在發(fā)送端進(jìn)行封包.

另:對(duì)于UDP來(lái)說(shuō)就不存在拆包的問題,因?yàn)閁DP是個(gè)"數(shù)據(jù)包"協(xié)議,也就是兩段數(shù)據(jù)間是有界限的,在接收端要么接收不到數(shù)據(jù)要么就是接收一個(gè)完整的一段數(shù)據(jù),不會(huì)少接收也不會(huì)多接收.

為什么會(huì)出現(xiàn)B.C.D的情況

"粘包"可發(fā)生在發(fā)送端也可發(fā)生在接收端.

1.由Nagle算法造成的發(fā)送端的粘包:Nagle算法是一種改善網(wǎng)絡(luò)傳輸效率的算法.簡(jiǎn)單的說(shuō),當(dāng)我們提交一段數(shù)據(jù)給TCP發(fā)送時(shí),TCP并不立刻發(fā)送此段數(shù)據(jù),而是等待一小段時(shí)間,看看在等待期間是否還有要發(fā)送的數(shù)據(jù),若有則會(huì)一次把這兩段數(shù)據(jù)發(fā)送出去.這是對(duì)Nagle算法一個(gè)簡(jiǎn)單的解釋,詳細(xì)的請(qǐng)看相關(guān)書籍.象C和D的情況就有可能是Nagle算法造成的.

2.接收端接收不及時(shí)造成的接收端粘包:TCP會(huì)把接收到的數(shù)據(jù)存在自己的緩沖區(qū)中,然后通知應(yīng)用層取數(shù)據(jù).當(dāng)應(yīng)用層由于某些原因不能及時(shí)的把TCP的數(shù)據(jù)取出來(lái),就會(huì)造成TCP緩沖區(qū)中存放了幾段數(shù)據(jù).

怎樣封包和拆包

最初遇到"粘包"的問題時(shí),我是通過(guò)在兩次send之間調(diào)用sleep來(lái)休眠一小段時(shí)間來(lái)解決.這個(gè)解決方法的缺點(diǎn)是顯而易見的,使傳輸效率大大降低,而且也并不可靠.后來(lái)就是通過(guò)應(yīng)答的方式來(lái)解決,盡管在大多數(shù)時(shí)候是可行的,但是不能解決象B的那種情況,而且采用應(yīng)答方式增加了通訊量,加重了網(wǎng)絡(luò)負(fù)荷. 再后來(lái)就是對(duì)數(shù)據(jù)包進(jìn)行封包和拆包的操作.

封包: 封包就是給一段數(shù)據(jù)加上包頭,這樣一來(lái)數(shù)據(jù)包就分為包頭和包體兩部分內(nèi)容了(以后講過(guò)濾非法包時(shí)封包會(huì)加入"包尾"內(nèi)容).包頭其實(shí)上是個(gè)大小固定的結(jié)構(gòu)體,其中有個(gè)結(jié)構(gòu)體成員變量表示包體的長(zhǎng)度,這是個(gè)很重要的變量,其他的結(jié)構(gòu)體成員可根據(jù)需要自己定義.根據(jù)包頭長(zhǎng)度固定以及包頭中含有包體長(zhǎng)度的變量就能正確的拆分出一個(gè)完整的數(shù)據(jù)包.

對(duì)于拆包目前我最常用的是以下兩種方式. 1.動(dòng)態(tài)緩沖區(qū)暫存方式.之所以說(shuō)緩沖區(qū)是動(dòng)態(tài)的是因?yàn)楫?dāng)需要緩沖的數(shù)據(jù)長(zhǎng)度超出緩沖區(qū)的長(zhǎng)度時(shí)會(huì)增大緩沖區(qū)長(zhǎng)度. 大概過(guò)程描述如下: A,為每一個(gè)連接動(dòng)態(tài)分配一個(gè)緩沖區(qū),同時(shí)把此緩沖區(qū)和SOCKET關(guān)聯(lián),常用的是通過(guò)結(jié)構(gòu)體關(guān)聯(lián). B,當(dāng)接收到數(shù)據(jù)時(shí)首先把此段數(shù)據(jù)存放在緩沖區(qū)中. C,判斷緩存區(qū)中的數(shù)據(jù)長(zhǎng)度是否夠一個(gè)包頭的長(zhǎng)度,如不夠,則不進(jìn)行拆包操作. D,根據(jù)包頭數(shù)據(jù)解析出里面代表包體長(zhǎng)度的變量. E,判斷緩存區(qū)中除包頭外的數(shù)據(jù)長(zhǎng)度是否夠一個(gè)包體的長(zhǎng)度,如不夠,則不進(jìn)行拆包操作. F,取出整個(gè)數(shù)據(jù)包.這里的"取"的意思是不光從緩沖區(qū)中拷貝出數(shù)據(jù)包,而且要把此數(shù)據(jù)包從緩存區(qū)中刪除掉.刪除的辦法就是把此包后面的數(shù)據(jù)移動(dòng)到緩沖區(qū)的起始地址.

這種方法有兩個(gè)缺點(diǎn).1.為每個(gè)連接動(dòng)態(tài)分配一個(gè)緩沖區(qū)增大了內(nèi)存的使用.2.有三個(gè)地方需要拷貝數(shù)據(jù),一個(gè)地方是把數(shù)據(jù)存放在緩沖區(qū),一個(gè)地方是把完整的數(shù)據(jù)包從緩沖區(qū)取出來(lái),一個(gè)地方是把數(shù)據(jù)包從緩沖區(qū)中刪除.第二種拆包的方法會(huì)解決和完善這些缺點(diǎn).

前面提到過(guò)這種方法的缺點(diǎn).下面給出一個(gè)改進(jìn)辦法, 即采用環(huán)形緩沖.但是這種改進(jìn)方法還是不能解決第一個(gè)缺點(diǎn)以及第一個(gè)數(shù)據(jù)拷貝,只能解決第三個(gè)地方的數(shù)據(jù)拷貝(這個(gè)地方是拷貝數(shù)據(jù)最多的地方).第2種拆包方式會(huì)解決這兩個(gè)問題. 環(huán)形緩沖實(shí)現(xiàn)方案是定義兩個(gè)指針,分別指向有效數(shù)據(jù)的頭和尾.在存放數(shù)據(jù)和刪除數(shù)據(jù)時(shí)只是進(jìn)行頭尾指針的移動(dòng).

2.利用底層的緩沖區(qū)來(lái)進(jìn)行拆包 由于TCP也維護(hù)了一個(gè)緩沖區(qū),所以我們完全可以利用TCP的緩沖區(qū)來(lái)緩存我們的數(shù)據(jù),這樣一來(lái)就不需要為每一個(gè)連接分配一個(gè)緩沖區(qū)了.另一方面我們知道recv或者wsarecv都有一個(gè)參數(shù),用來(lái)表示我們要接收多長(zhǎng)長(zhǎng)度的數(shù)據(jù).利用這兩個(gè)條件我們就可以對(duì)第一種方法進(jìn)行優(yōu)化. 對(duì)于阻塞SOCKET來(lái)說(shuō),我們可以利用一個(gè)循環(huán)來(lái)接收包頭長(zhǎng)度的數(shù)據(jù),然后解析出代表包體長(zhǎng)度的那個(gè)變量,再用一個(gè)循環(huán)來(lái)接收包體長(zhǎng)度的數(shù)據(jù). 相關(guān)代碼如下:

char PackageHead[1024];
char PackageContext[1024*20];

int len;
PACKAGE_HEAD *pPackageHead;
while( m_bClose == false )
{
memset(PackageHead,0,sizeof(PACKAGE_HEAD));
len = m_TcpSock.ReceiveSize((char*)PackageHead,sizeof(PACKAGE_HEAD));
if( len == SOCKET_ERROR )
{
    break;
}
if(len == 0)
{
    break;
}
pPackageHead = (PACKAGE_HEAD *)PackageHead;
memset(PackageContext,0,sizeof(PackageContext));
if(pPackageHead- >nDataLen >0)
{
len = m_TcpSock.ReceiveSize((char*)PackageContext,pPackageHead- >nDataLen);
}
        }

m_TcpSock是一個(gè)封裝了SOCKET的類的變量,其中的ReceiveSize用于接收一定長(zhǎng)度的數(shù)據(jù),直到接收了一定長(zhǎng)度的數(shù)據(jù)或者網(wǎng)絡(luò)出錯(cuò)才返回.

int winSocket::ReceiveSize( char* strData, int iLen )
{
if( strData == NULL )
return ERR_BADPARAM;
char *p = strData;
int len = iLen;
int ret = 0;
int returnlen = 0;
while( len > 0)
{
ret = recv( m_hSocket, p+(iLen-len), iLen-returnlen, 0 );
if ( ret == SOCKET_ERROR || ret == 0 )
{
return ret;
}

len -= ret;
returnlen += ret;
}

return returnlen;
}

對(duì)于非阻塞的SOCKET,比如完成端口,我們可以提交接收包頭長(zhǎng)度的數(shù)據(jù)的請(qǐng)求,當(dāng) GetQueuedCompletionStatus返回時(shí),我們判斷接收的數(shù)據(jù)長(zhǎng)度是否等于包頭長(zhǎng)度,若等于,則提交接收包體長(zhǎng)度的數(shù)據(jù)的請(qǐng)求,若不等于則提交接收剩余數(shù)據(jù)的請(qǐng)求.當(dāng)接收包體時(shí),采用類似的方法.

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 操作系統(tǒng)
    +關(guān)注

    關(guān)注

    37

    文章

    6747

    瀏覽量

    123202
  • 緩存
    +關(guān)注

    關(guān)注

    1

    文章

    233

    瀏覽量

    26649
  • 數(shù)據(jù)包
    +關(guān)注

    關(guān)注

    0

    文章

    253

    瀏覽量

    24367
  • TCP通信
    +關(guān)注

    關(guān)注

    0

    文章

    146

    瀏覽量

    4217
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    嵌入式TCP/IP協(xié)議單片機(jī)技術(shù)在網(wǎng)絡(luò)通信中的應(yīng)用

    介紹了嵌入式TCP/IP協(xié)議單片機(jī)在網(wǎng)絡(luò)通信中的數(shù)據(jù)傳輸技術(shù)。將TCP/IP協(xié)議嵌入式單片機(jī)中,借助網(wǎng)卡芯片CS8900實(shí)現(xiàn)了單片機(jī)在局域網(wǎng)內(nèi)和通過(guò)局域網(wǎng)在因特網(wǎng)上的數(shù)據(jù)傳輸。用戶終端以單片機(jī)系統(tǒng)板為媒介,通過(guò)網(wǎng)絡(luò)與遠(yuǎn)程數(shù)據(jù)終端
    發(fā)表于 05-13 11:17 ?5490次閱讀

    lwip tcp的原因?

    使用lwip協(xié)議棧,作為客戶端應(yīng)答2幀數(shù)據(jù)時(shí),會(huì)有問題,在tcp write 后調(diào)用tcp output沒有效果,設(shè)置 #define TF_NODELAY((u8_t)0x40U
    發(fā)表于 05-10 06:51

    esp8266讀取模擬數(shù)據(jù)并記錄到eeprom,發(fā)送tcp時(shí)無(wú)法讀取模擬如何解決?

    嗨,esp8266 讀取模擬數(shù)據(jù)并記錄到 eeprom,我正在將存儲(chǔ)在 eeprom 中的數(shù)據(jù)作為 tcp 發(fā)送,但在發(fā)送 tcp 時(shí)無(wú)法讀取模擬,如
    發(fā)表于 07-11 07:22

    labview通信中如果有通信協(xié)議,如何處理通信中傳輸?shù)膮f(xié)議數(shù)據(jù)?

    我要接受的數(shù)據(jù)在一個(gè)數(shù)據(jù)中,通信中數(shù)據(jù)一位一位的傳輸,我現(xiàn)在想將通信的過(guò)程中(實(shí)時(shí))將數(shù)據(jù)分別提取出來(lái),該如何實(shí)現(xiàn)?
    發(fā)表于 04-11 15:31

    tcp通信中,在不知道tcp讀取字節(jié)數(shù)多少的情況下,應(yīng)該如何設(shè)定tcp讀取的字節(jié)數(shù)?

    tcp通信中,在不知道tcp讀取字節(jié)數(shù)多少的情況下,應(yīng)該如何設(shè)定tcp讀取的字節(jié)數(shù)。具體的情況是返回一組十六進(jìn)制的字符串,但不知道字符串長(zhǎng)度應(yīng)該如何設(shè)定
    發(fā)表于 11-24 17:56

    為什么stm32107lwip+modbus tcp通信中會(huì)提示傳輸id錯(cuò)誤?

    原子哥:請(qǐng)教個(gè)問題,stm32107lwip+modbus tcp(無(wú)系統(tǒng))通信中,用modbus poll下發(fā)以后就提示傳輸id錯(cuò)誤,還有就是超時(shí),???、
    發(fā)表于 07-17 04:35

    嵌入式TCP/IP協(xié)議單片機(jī)在網(wǎng)絡(luò)通信中有什么應(yīng)用?

    什么是TCP/IP協(xié)議?CS8900的工作原理是什么?嵌入式TCP/IP協(xié)議單片機(jī)在網(wǎng)絡(luò)通信中有什么應(yīng)用?
    發(fā)表于 06-04 06:49

    Labview TCP通信 數(shù)據(jù)分包和處理。

    Labview的TCP通信的讀函數(shù),會(huì)發(fā)生數(shù)據(jù)分包和嗎?應(yīng)該怎么處理TCP讀數(shù)據(jù),官方的例子沒有考慮。
    發(fā)表于 03-22 14:02

    Labview TCP通信問題

    labview的TCP通信的讀函數(shù),會(huì)發(fā)生數(shù)據(jù)分包和嗎?應(yīng)該怎么處理TCP讀數(shù)據(jù),官方的例子沒有考慮。
    發(fā)表于 03-22 14:07

    TCP/IP協(xié)議單片機(jī)在網(wǎng)絡(luò)通信中的數(shù)據(jù)傳輸技術(shù)

    介紹了嵌入式TCP/IP協(xié)議單片機(jī)在網(wǎng)絡(luò)通信中的數(shù)據(jù)傳輸技術(shù)。將TCP/IP協(xié)議嵌入式單片機(jī)中,借助網(wǎng)卡芯片CS8900實(shí)現(xiàn)了單片機(jī)在局域網(wǎng)內(nèi)和通過(guò)局域網(wǎng)在因特網(wǎng)上的數(shù)據(jù)傳輸。用戶終端以單
    發(fā)表于 04-16 22:04 ?4411次閱讀
    <b class='flag-5'>TCP</b>/IP協(xié)議單片機(jī)在網(wǎng)絡(luò)<b class='flag-5'>通信中</b>的數(shù)據(jù)傳輸技術(shù)

    TCP到底是什么

    TCP是一種流式連接,對(duì)小包會(huì)進(jìn)行封包緩存發(fā)送,大包會(huì)出現(xiàn)分包發(fā)送。接收端就會(huì)發(fā)現(xiàn)接收到的數(shù)據(jù)和發(fā)送的數(shù)據(jù)的次數(shù)不一致。這個(gè)就是現(xiàn)象。
    的頭像 發(fā)表于 02-17 17:45 ?4093次閱讀

    何解TCP報(bào)文的內(nèi)容

    TCP協(xié)議有著自己的數(shù)據(jù)格式,這里把TCP的數(shù)據(jù)稱為報(bào)文段(segment),TCP報(bào)文段封裝在IP數(shù)據(jù)報(bào)中發(fā)送,
    的頭像 發(fā)表于 08-31 09:12 ?2706次閱讀

    【推薦】TCP為何問題如何解決?

    我們?cè)谏婕?b class='flag-5'>TCP協(xié)議的應(yīng)用中,經(jīng)常會(huì)出現(xiàn)的問題。所謂,簡(jiǎn)單地講,就是我有兩條消息,明明發(fā)送端的代碼是分兩次發(fā)送的,但是在接收端卻一次
    的頭像 發(fā)表于 09-23 10:00 ?829次閱讀
    【推薦】<b class='flag-5'>TCP</b>為何<b class='flag-5'>粘</b><b class='flag-5'>包</b>?<b class='flag-5'>粘</b><b class='flag-5'>包</b>問題如<b class='flag-5'>何解</b>決?

    tcp究竟會(huì)帶來(lái)多大的性能問題

    一個(gè)項(xiàng)目對(duì)接第三方接口數(shù)據(jù)。對(duì)方是TCP接口,發(fā)送數(shù)據(jù)頻率很高。平均2毫秒發(fā)送三四千個(gè)字節(jié)。由于TCP協(xié)議的問題,我這里接收到的數(shù)據(jù)
    的頭像 發(fā)表于 11-08 16:16 ?1273次閱讀
    <b class='flag-5'>tcp</b>丟<b class='flag-5'>包</b>究竟會(huì)帶來(lái)多大的性能問題

    TCP和拆包產(chǎn)生的原因

    一、TCP現(xiàn)象 what? TCP是個(gè)“流”協(xié)議,即沒有邊界。由于這個(gè)特性以及實(shí)際的網(wǎng)絡(luò)情況,在進(jìn)行數(shù)據(jù)傳輸時(shí)假設(shè)我們連續(xù)調(diào)用send分別發(fā)送兩段數(shù)據(jù)data1和data2,在接收
    的頭像 發(fā)表于 11-10 14:07 ?825次閱讀
    <b class='flag-5'>TCP</b><b class='flag-5'>粘</b><b class='flag-5'>包</b>和拆包產(chǎn)生的原因