TCP是基于流式傳輸?shù)?/h1>

TCP為了保證可靠傳輸,盡量減少額外開銷(每次發(fā)包都要驗證)麻车,因此采用了流式傳輸缀皱,面向流的傳輸,相對于面向消息的傳輸动猬,可以減少發(fā)送包的數(shù)量啤斗,從而減少了額外開銷。但是赁咙,對于數(shù)據(jù)傳輸頻繁的程序來講钮莲,使用TCP可能會容易粘包。當然彼水,對接收端的程序來講崔拥,如果機器負荷很重,也會在接收緩沖里粘包凤覆。這樣链瓦,就需要接收端額外拆包,增加了工作量盯桦。因此慈俯,這個特別適合的是數(shù)據(jù)要求可靠傳輸,但是不需要太頻繁傳輸?shù)膱龊希▋纱尾僮鏖g隔100ms拥峦,具體是由TCP等待發(fā)送間隔決定的贴膘,取決于內(nèi)核中的socket的寫法)

(2)UDP,由于面向的是消息傳輸事镣,它把所有接收到的消息都掛接到緩沖區(qū)的接受隊列中步鉴,因此揪胃,它對于數(shù)據(jù)的提取分離就更加方便璃哟,但是氛琢,它沒有粘包機制,因此随闪,當發(fā)送數(shù)據(jù)量較小的時候阳似,就會發(fā)生數(shù)據(jù)包有效載荷較小的情況,也會增加多次發(fā)送的系統(tǒng)發(fā)送開銷(系統(tǒng)調(diào)用铐伴,寫硬件等)和接收開銷撮奏。因此,應該最好設置一個比較合適的數(shù)據(jù)包的包長当宴,來進行UDP數(shù)據(jù)的發(fā)送畜吊。(UDP最大載荷為1472,因此最好能每次傳輸接近這個數(shù)的數(shù)據(jù)量户矢,這特別適合于視頻玲献,音頻等大塊數(shù)據(jù)的發(fā)送,同時梯浪,通過減少握手來保證流媒體的實時性)

====================================================================

粘包問題分析與對策

TCP粘包是指發(fā)送方發(fā)送的若干包數(shù)據(jù)到接收方接收時粘成一包捌年,從接收緩沖區(qū)看,后一包數(shù)據(jù)的頭緊接著前一包數(shù)據(jù)的尾挂洛。

出現(xiàn)粘包現(xiàn)象的原因是多方面的礼预,它既可能由發(fā)送方造成,也可能由接收方造成虏劲。

什么時候需要考慮粘包問題

1如果利用tcp每次發(fā)送數(shù)據(jù)托酸,就與對方建立連接,然后雙方發(fā)送完一段數(shù)據(jù)后柒巫,就關(guān)閉連接励堡,這樣就不會出現(xiàn)粘包問題(因為只有一種包結(jié)構(gòu),類似于http協(xié)議)。

關(guān)閉連接主要是要雙方都發(fā)送close連接(參考tcp關(guān)閉協(xié)議)吻育。如:A需要發(fā)送一段字符串給B念秧,那么A與B建立連接,然后發(fā)送雙方都默認好的協(xié)議字符如"hello give me sth abour yourself"布疼,然后B收到報文后摊趾,就將緩沖區(qū)數(shù)據(jù)接收,然后關(guān)閉連接游两,這樣粘包問題不用考慮到砾层,因為大家都知道是發(fā)送一段字符。

2如果發(fā)送數(shù)據(jù)無結(jié)構(gòu)贱案,如文件傳輸肛炮,這樣發(fā)送方只管發(fā)送,接收方只管接收存儲就ok,也不用考慮粘包3如果雙方建立連接侨糟,需要在連接后一段時間內(nèi)發(fā)送不同結(jié)構(gòu)數(shù)據(jù)碍扔,如連接后,有好幾種結(jié)構(gòu):

1)"hellogive me sth abour yourself"

2)"Don'tgive me sth abour yourself"

那這樣的話秕重,如果發(fā)送方連續(xù)發(fā)送這個兩個包出去不同,接收方一次接收可能會是"hellogive me sth abour yourselfDon't give me sth abour yourself"這樣接收方就傻了,到底是要干嘛溶耘?不知道二拐,因為協(xié)議沒有規(guī)定這么詭異的字符串,所以要處理把它分包凳兵,怎么分也需要雙方組織一個比較好的包結(jié)構(gòu)百新,所以一般可能會在頭加一個數(shù)據(jù)長度之類的包,以確保接收庐扫。

TCP無保護消息邊界的解決

針對這個問題饭望,一般有3種解決方案:

(1)發(fā)送固定長度的消息

(2)把消息的尺寸與消息一塊發(fā)送

(3)使用特殊標記來區(qū)分消息間隔

為什么基于TCP的通訊程序需要進行封包和拆包

TCP是個"流"協(xié)議,所謂流聚蝶,就是沒有界限的一串數(shù)據(jù)杰妓,大家可以想想河里的流水,是連成一片的碘勉,其間是沒有分界線的巷挥。但一般通訊程序開發(fā)是需要定義一個個相互獨立的數(shù)據(jù)包的,比如用于登陸的數(shù)據(jù)包验靡,用于注銷的數(shù)據(jù)包倍宾。由于TCP"流"的特性以及網(wǎng)絡狀況,在進行數(shù)據(jù)傳輸時會出現(xiàn)以下幾種情況胜嗓。

假設我們連續(xù)調(diào)用兩次send分別發(fā)送兩段數(shù)據(jù)data1和data2,在接收端有以下幾種接收情況(當然不止這幾種情況,這里只列出了有代表性的情況).

A.先接收到data1,然后接收到data2.

B.先接收到data1的部分數(shù)據(jù),然后接收到data1余下的部分以及data2的全部.

C.先接收到了data1的全部數(shù)據(jù)和data2的部分數(shù)據(jù),然后接收到了data2的余下的數(shù)據(jù).

D.一次性接收到了data1和data2的全部數(shù)據(jù).

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

另:對于UDP來說就不存在拆包的問題,因為UDP是個"數(shù)據(jù)包"協(xié)議,也就是兩段數(shù)據(jù)間是有界限的怔锌,在接收端要么接收不到數(shù)據(jù)要么就是接收一個完整的一段數(shù)據(jù),不會少接收也不會多接收变过。

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

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

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

怎樣封包和拆包

最初遇到"粘包"的問題時,我是通過在兩次send之間調(diào)用sleep來休眠一小段時間來解決埃元。這個解決方法的缺點是顯而易見的,使傳輸效率大大降低媚狰,而且也并不可靠岛杀。后來就是通過應答的方式來解決,盡管在大多數(shù)時候是可行的崭孤,但是不能解決B的那種情況类嗤,而且采用應答方式增加了通訊量,加重了網(wǎng)絡負荷. 再后來就是對數(shù)據(jù)包進行封包和拆包的操作糊肠。

封包

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

拆包

對于拆包目前我最常用的是以下兩種方式:

(1)動態(tài)緩沖區(qū)暫存方式派殷。之所以說緩沖區(qū)是動態(tài)的是因為當需要緩沖的數(shù)據(jù)長度超出緩沖區(qū)的長度時會增大緩沖區(qū)長度还最。

大概過程描述如下:

A,為每一個連接動態(tài)分配一個緩沖區(qū),同時把此緩沖區(qū)和SOCKET關(guān)聯(lián),常用的是通過結(jié)構(gòu)體關(guān)聯(lián).

B,當接收到數(shù)據(jù)時首先把此段數(shù)據(jù)存放在緩沖區(qū)中.

C,判斷緩存區(qū)中的數(shù)據(jù)長度是否夠一個包頭的長度,如不夠,則不進行拆包操作.

D,根據(jù)包頭數(shù)據(jù)解析出里面代表包體長度的變量.

E,判斷緩存區(qū)中除包頭外的數(shù)據(jù)長度是否夠一個包體的長度,如不夠,則不進行拆包操作.

F,取出整個數(shù)據(jù)包.這里的"取"的意思是不光從緩沖區(qū)中拷貝出數(shù)據(jù)包,而且要把此數(shù)據(jù)包從緩存區(qū)中刪除掉.刪除的辦法就是把此包后面的數(shù)據(jù)移動到緩沖區(qū)的起始地址.

這種方法有兩個缺點.

1) 為每個連接動態(tài)分配一個緩沖區(qū)增大了內(nèi)存的使用.

2) 有三個地方需要拷貝數(shù)據(jù),一個地方是把數(shù)據(jù)存放在緩沖區(qū),一個地方是把完整的數(shù)據(jù)包從緩沖區(qū)取出來,一個地方是把數(shù)據(jù)包從緩沖區(qū)中刪除.第二種拆包的方法會解決和完善這些缺點.

前面提到過這種方法的缺點.下面給出一個改進辦法, 即采用環(huán)形緩沖.但是這種改進方法還是不能解決第一個缺點以及第一個數(shù)據(jù)拷貝,只能解決第三個地方的數(shù)據(jù)拷貝(這個地方是拷貝數(shù)據(jù)最多的地方).第2種拆包方式會解決這兩個問題.

環(huán)形緩沖實現(xiàn)方案是定義兩個指針,分別指向有效數(shù)據(jù)的頭和尾.在存放數(shù)據(jù)和刪除數(shù)據(jù)時只是進行頭尾指針的移動.

(2)利用底層的緩沖區(qū)來進行拆包

由于TCP也維護了一個緩沖區(qū),所以我們完全可以利用TCP的緩沖區(qū)來緩存我們的數(shù)據(jù),這樣一來就不需要為每一個連接分配一個緩沖區(qū)了毡惜。另一方面我們知道recv或者wsarecv都有一個參數(shù),用來表示我們要接收多長長度的數(shù)據(jù)拓轻。利用這兩個條件我們就可以對第一種方法進行優(yōu)化。

對于阻塞SOCKET來說经伙,我們可以利用一個循環(huán)來接收包頭長度的數(shù)據(jù)扶叉,然后解析出代表包體長度的那個變量,再用一個循環(huán)來接收包體長度的數(shù)據(jù)帕膜。

轉(zhuǎn)載 http://www.cnblogs.com/kex1n/p/6502002.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者

  • 序言:七十年代末枣氧,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子垮刹,更是在濱河造成了極大的恐慌达吞,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,744評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件荒典,死亡現(xiàn)場離奇詭異酪劫,居然都是意外死亡,警方通過查閱死者的電腦和手機寺董,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評論 3 392
  • 文/潘曉璐 我一進店門覆糟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人遮咖,你說我怎么就攤上這事滩字。” “怎么了御吞?”我有些...
    開封第一講書人閱讀 163,105評論 0 353
  • 文/不壞的土叔 我叫張陵麦箍,是天一觀的道長。 經(jīng)常有香客問我魄藕,道長内列,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,242評論 1 292
  • 正文 為了忘掉前任背率,我火速辦了婚禮话瞧,結(jié)果婚禮上嫩与,老公的妹妹穿的比我還像新娘。我一直安慰自己交排,他們只是感情好划滋,可當我...
    茶點故事閱讀 67,269評論 6 389
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著埃篓,像睡著了一般处坪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上架专,一...
    開封第一講書人閱讀 51,215評論 1 299
  • 那天同窘,我揣著相機與錄音,去河邊找鬼部脚。 笑死想邦,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的委刘。 我是一名探鬼主播丧没,決...
    沈念sama閱讀 40,096評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼锡移!你這毒婦竟也來了呕童?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,939評論 0 274
  • 序言:老撾萬榮一對情侶失蹤淆珊,失蹤者是張志新(化名)和其女友劉穎夺饲,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體套蒂,經(jīng)...
    沈念sama閱讀 45,354評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡钞支,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,573評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了操刀。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片烁挟。...
    茶點故事閱讀 39,745評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖骨坑,靈堂內(nèi)的尸體忽然破棺而出撼嗓,到底是詐尸還是另有隱情,我是刑警寧澤欢唾,帶...
    沈念sama閱讀 35,448評論 5 344
  • 正文 年R本政府宣布且警,位于F島的核電站,受9級特大地震影響礁遣,放射性物質(zhì)發(fā)生泄漏斑芜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,048評論 3 327
  • 文/蒙蒙 一祟霍、第九天 我趴在偏房一處隱蔽的房頂上張望杏头。 院中可真熱鬧盈包,春花似錦、人聲如沸醇王。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽寓娩。三九已至叛氨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間棘伴,已是汗流浹背寞埠。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留排嫌,地道東北人畸裳。 一個月前我還...
    沈念sama閱讀 47,776評論 2 369
  • 正文 我出身青樓,卻偏偏與公主長得像淳地,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子帅容,可洞房花燭夜當晚...
    茶點故事閱讀 44,652評論 2 354

推薦閱讀更多精彩內(nèi)容