阿里Java高級(jí)架構(gòu)面試:熟悉TCP粘包寻仗、拆包刃泌?

聲明:本文來自知乎,侵刪署尤。

一耙替、TCP粘包、拆包圖解

假設(shè)客戶端分別發(fā)送了兩個(gè)數(shù)據(jù)包D1和D2給服務(wù)端曹体,由于服務(wù)端一次讀取到字節(jié)數(shù)是不確定的俗扇,故可能存在以下四種情況:

服務(wù)端分兩次讀取到了兩個(gè)獨(dú)立的數(shù)據(jù)包,分別是D1和D2箕别,沒有粘包和拆包

服務(wù)端一次接受到了兩個(gè)數(shù)據(jù)包铜幽,D1和D2粘合在一起滞谢,稱之為TCP粘包

服務(wù)端分兩次讀取到了數(shù)據(jù)包,第一次讀取到了完整的D1包和D2包的部分內(nèi)容除抛,第二次讀取到了D2包的剩余內(nèi)容狮杨,這稱之為TCP拆包

服務(wù)端分兩次讀取到了數(shù)據(jù)包,第一次讀取到了D1包的部分內(nèi)容D1_1到忽,第二次讀取到了D1包的剩余部分內(nèi)容D1_2和完整的D2包橄教。

特別要注意的是,如果TCP的接受滑窗非常小喘漏,而數(shù)據(jù)包D1和D2比較大护蝶,很有可能會(huì)發(fā)生第五種情況,即服務(wù)端分多次才能將D1和D2包完全接受翩迈,期間發(fā)生多次拆包持灰。

二、 粘包帽馋、拆包產(chǎn)生原因

產(chǎn)生原因主要有這3種:

滑動(dòng)窗口

MSS/MTU限制

Nagle算法

1搅方、滑動(dòng)窗口

TCP流量控制主要使用滑動(dòng)窗口協(xié)議,滑動(dòng)窗口是接受數(shù)據(jù)端使用的窗口大小绽族,用來告訴發(fā)送端接收端的緩存大小姨涡,以此可以控制發(fā)送端發(fā)送數(shù)據(jù)的大小,從而達(dá)到流量控制的目的吧慢。這個(gè)窗口大小就是我們一次傳輸幾個(gè)數(shù)據(jù)涛漂。對(duì)所有數(shù)據(jù)幀按順序賦予編號(hào),發(fā)送方在發(fā)送過程中始終保持著一個(gè)發(fā)送窗口检诗,只有落在發(fā)送窗口內(nèi)的幀才允許被發(fā)送匈仗;同時(shí)接收方也維持著一個(gè)接收窗口,只有落在接收窗口內(nèi)的幀才允許接收逢慌。這樣通過調(diào)整發(fā)送方窗口和接收方窗口的大小可以實(shí)現(xiàn)流量控制悠轩。

現(xiàn)在來看一下滑動(dòng)窗口是如何造成粘包、拆包的攻泼?

粘包:假設(shè)發(fā)送方的每256 bytes表示一個(gè)完整的報(bào)文火架,接收方由于數(shù)據(jù)處理不及時(shí),這256個(gè)字節(jié)的數(shù)據(jù)都會(huì)被緩存到SO_RCVBUF(接收緩存區(qū))中忙菠。如果接收方的SO_RCVBUF中緩存了多個(gè)報(bào)文何鸡,那么對(duì)于接收方而言,這就是粘包牛欢。

拆包:考慮另外一種情況骡男,假設(shè)接收方的窗口只剩了128,意味著發(fā)送方最多還可以發(fā)送128字節(jié)傍睹,而由于發(fā)送方的數(shù)據(jù)大小是256字節(jié)隔盛,因此只能發(fā)送前128字節(jié)犹菱,等到接收方ack后,才能發(fā)送剩余字節(jié)骚亿。這就造成了拆包已亥。

2熊赖、MSS和MTU分片

MSS:?是Maximum Segement Size縮寫来屠,表示TCP報(bào)文中data部分的最大長度,是TCP協(xié)議在OSI五層網(wǎng)絡(luò)模型中傳輸層對(duì)一次可以發(fā)送的最大數(shù)據(jù)的限制震鹉。

MTU:?最大傳輸單元是Maxitum Transmission Unit的簡寫俱笛,是OSI五層網(wǎng)絡(luò)模型中鏈路層(datalink layer)對(duì)一次可以發(fā)送的最大數(shù)據(jù)的限制。

當(dāng)需要傳輸?shù)臄?shù)據(jù)大于MSS或者M(jìn)TU時(shí)传趾,數(shù)據(jù)會(huì)被拆分成多個(gè)包進(jìn)行傳輸迎膜。由于MSS是根據(jù)MTU計(jì)算出來的,因此當(dāng)發(fā)送的數(shù)據(jù)滿足MSS時(shí)浆兰,必然滿足MTU磕仅。

為了更好的理解,我們先介紹一下在5層網(wǎng)絡(luò)模型中應(yīng)用通過TCP發(fā)送數(shù)據(jù)的流程:

對(duì)于應(yīng)用層來說簸呈,只關(guān)心發(fā)送的數(shù)據(jù)DATA榕订,將數(shù)據(jù)寫入socket在內(nèi)核中的發(fā)送緩沖區(qū)SO_SNDBUF即返回,操作系統(tǒng)會(huì)將SO_SNDBUF中的數(shù)據(jù)取出來進(jìn)行發(fā)送蜕便。傳輸層會(huì)在DATA前面加上TCP Header,構(gòu)成一個(gè)完整的TCP報(bào)文劫恒。

當(dāng)數(shù)據(jù)到達(dá)網(wǎng)絡(luò)層(network layer)時(shí),網(wǎng)絡(luò)層會(huì)在TCP報(bào)文的基礎(chǔ)上再添加一個(gè)IP Header轿腺,也就是將自己的網(wǎng)絡(luò)地址加入到報(bào)文中两嘴。到數(shù)據(jù)鏈路層時(shí),還會(huì)加上Datalink Header和CRC族壳。

當(dāng)?shù)竭_(dá)物理層時(shí)憔辫,會(huì)將SMAC(Source Machine,數(shù)據(jù)發(fā)送方的MAC地址)仿荆,DMAC(Destination Machine贰您,數(shù)據(jù)接受方的MAC地址 )和Type域加入。

可以發(fā)現(xiàn)數(shù)據(jù)在發(fā)送前赖歌,每一層都會(huì)在上一層的基礎(chǔ)上增加一些內(nèi)容枉圃,下圖演示了MSS、MTU在這個(gè)過程中的作用庐冯。


MTU是以太網(wǎng)傳輸數(shù)據(jù)方面的限制孽亲,每個(gè)以太網(wǎng)幀都有最小的大小64bytes最大不能超過1518bytes。刨去以太網(wǎng)幀的幀頭 (DMAC目的MAC地址48bit=6Bytes+SMAC源MAC地址48bit=6Bytes+Type域2bytes)14Bytes和幀尾 CRC校驗(yàn)部分4Bytes(這個(gè)部分有時(shí)候大家也把它叫做FCS)展父,那么剩下承載上層協(xié)議的地方也就是Data域最大就只能有1500Bytes這個(gè)值 我們就把它稱之為MTU返劲。

由于MTU限制了一次最多可以發(fā)送1500個(gè)字節(jié)玲昧,而TCP協(xié)議在發(fā)送DATA時(shí),還會(huì)加上額外的TCP Header和Ip Header篮绿,因此刨去這兩個(gè)部分孵延,就是TCP協(xié)議一次可以發(fā)送的實(shí)際應(yīng)用數(shù)據(jù)的最大大小,也就是MSS亲配。

MSS長度=MTU長度-IP Header-TCP Header

TCP Header的長度是20字節(jié)尘应,IPv4中IP Header長度是20字節(jié),IPV6中IP Header長度是40字節(jié)吼虎,因此:在IPV4中犬钢,以太網(wǎng)MSS可以達(dá)到1460byte;在IPV6中思灰,以太網(wǎng)MSS可以達(dá)到1440byte玷犹。

需要注意的是MSS表示的一次可以發(fā)送的DATA的最大長度,而不是DATA的真實(shí)長度洒疚。發(fā)送方發(fā)送數(shù)據(jù)時(shí)歹颓,當(dāng)SO_SNDBUF中的數(shù)據(jù)量大于MSS時(shí),操作系統(tǒng)會(huì)將數(shù)據(jù)進(jìn)行拆分油湖,使得每一部分都小于MSS巍扛,這就是拆包,然后每一部分都加上TCP Header肺魁,構(gòu)成多個(gè)完整的TCP報(bào)文進(jìn)行發(fā)送电湘,當(dāng)然經(jīng)過網(wǎng)絡(luò)層和數(shù)據(jù)鏈路層的時(shí)候,還會(huì)分別加上相應(yīng)的內(nèi)容鹅经。

需要注意:?默認(rèn)情況下寂呛,與外部通信的網(wǎng)卡的MTU大小是1500個(gè)字節(jié)。而本地回環(huán)地址的MTU大小為65535瘾晃,這是因?yàn)楸镜販y試時(shí)數(shù)據(jù)不需要走網(wǎng)卡贷痪,所以不受到1500的限制。

3蹦误、 Nagle算法

TCP/IP協(xié)議中劫拢,無論發(fā)送多少數(shù)據(jù),總是要在數(shù)據(jù)(DATA)前面加上協(xié)議頭(TCP Header+IP Header)强胰,同時(shí)舱沧,對(duì)方接收到數(shù)據(jù),也需要發(fā)送ACK表示確認(rèn)偶洋。

即使從鍵盤輸入的一個(gè)字符熟吏,占用一個(gè)字節(jié),可能在傳輸上造成41字節(jié)的包,其中包括1字節(jié)的有用信息和40字節(jié)的首部數(shù)據(jù)牵寺。這種情況轉(zhuǎn)變成了4000%的消耗悍引,這樣的情況對(duì)于重負(fù)載的網(wǎng)絡(luò)來是無法接受的。

為了盡可能的利用網(wǎng)絡(luò)帶寬帽氓,TCP總是希望盡可能的發(fā)送足夠大的數(shù)據(jù)趣斤。(一個(gè)連接會(huì)設(shè)置MSS參數(shù),因此黎休,TCP/IP希望每次都能夠以MSS尺寸的數(shù)據(jù)塊來發(fā)送數(shù)據(jù))浓领。

Nagle算法就是為了盡可能發(fā)送大塊數(shù)據(jù),避免網(wǎng)絡(luò)中充斥著許多小數(shù)據(jù)塊奋渔。

Nagle算法的基本定義是任意時(shí)刻镊逝,最多只能有一個(gè)未被確認(rèn)的小段。 所謂“小段”嫉鲸,指的是小于MSS尺寸的數(shù)據(jù)塊,所謂“未被確認(rèn)”歹啼,是指一個(gè)數(shù)據(jù)塊發(fā)送出去后玄渗,沒有收到對(duì)方發(fā)送的ACK確認(rèn)該數(shù)據(jù)已收到。

Nagle算法的規(guī)則:

如果SO_SNDBUF(發(fā)送緩沖區(qū))中的數(shù)據(jù)長度達(dá)到MSS狸眼,則允許發(fā)送藤树;

如果該SO_SNDBUF中含有FIN,表示請(qǐng)求關(guān)閉連接拓萌,則先將SO_SNDBUF中的剩余數(shù)據(jù)發(fā)送岁钓,再關(guān)閉;

設(shè)置了TCP_NODELAY=true選項(xiàng)微王,則允許發(fā)送屡限。TCP_NODELAY是取消TCP的確認(rèn)延遲機(jī)制,相當(dāng)于禁用了Nagle 算法炕倘。

未設(shè)置TCP_CORK選項(xiàng)時(shí)钧大,若所有發(fā)出去的小數(shù)據(jù)包(包長度小于MSS)均被確認(rèn),則允許發(fā)送;

上述條件都未滿足罩旋,但發(fā)生了超時(shí)(一般為200ms)啊央,則立即發(fā)送。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末涨醋,一起剝皮案震驚了整個(gè)濱河市瓜饥,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌浴骂,老刑警劉巖乓土,帶你破解...
    沈念sama閱讀 221,406評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異靠闭,居然都是意外死亡帐我,警方通過查閱死者的電腦和手機(jī)坎炼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,395評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拦键,“玉大人谣光,你說我怎么就攤上這事》椅” “怎么了萄金?”我有些...
    開封第一講書人閱讀 167,815評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長媚朦。 經(jīng)常有香客問我氧敢,道長,這世上最難降的妖魔是什么询张? 我笑而不...
    開封第一講書人閱讀 59,537評(píng)論 1 296
  • 正文 為了忘掉前任孙乖,我火速辦了婚禮,結(jié)果婚禮上份氧,老公的妹妹穿的比我還像新娘唯袄。我一直安慰自己,他們只是感情好蜗帜,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,536評(píng)論 6 397
  • 文/花漫 我一把揭開白布恋拷。 她就那樣靜靜地躺著,像睡著了一般厅缺。 火紅的嫁衣襯著肌膚如雪蔬顾。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,184評(píng)論 1 308
  • 那天湘捎,我揣著相機(jī)與錄音诀豁,去河邊找鬼。 笑死消痛,一個(gè)胖子當(dāng)著我的面吹牛且叁,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播秩伞,決...
    沈念sama閱讀 40,776評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼逞带,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了纱新?” 一聲冷哼從身側(cè)響起展氓,我...
    開封第一講書人閱讀 39,668評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎脸爱,沒想到半個(gè)月后遇汞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,212評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,299評(píng)論 3 340
  • 正文 我和宋清朗相戀三年空入,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了络它。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,438評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡歪赢,死狀恐怖化戳,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情埋凯,我是刑警寧澤点楼,帶...
    沈念sama閱讀 36,128評(píng)論 5 349
  • 正文 年R本政府宣布,位于F島的核電站白对,受9級(jí)特大地震影響掠廓,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜甩恼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,807評(píng)論 3 333
  • 文/蒙蒙 一蟀瞧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧媳拴,春花似錦黄橘、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,279評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽抬探。三九已至子巾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間小压,已是汗流浹背线梗。 一陣腳步聲響...
    開封第一講書人閱讀 33,395評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留怠益,地道東北人仪搔。 一個(gè)月前我還...
    沈念sama閱讀 48,827評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像蜻牢,于是被迫代替她去往敵國和親烤咧。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,446評(píng)論 2 359

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

  • 轉(zhuǎn):http://www.tianshouzhi.com/api/tutorials/netty/343, htt...
    沉淪2014閱讀 2,580評(píng)論 0 20
  • 個(gè)人認(rèn)為,Goodboy1881先生的TCP /IP 協(xié)議詳解學(xué)習(xí)博客系列博客是一部非常精彩的學(xué)習(xí)筆記抱虐,這雖然只是...
    貳零壹柒_fc10閱讀 5,059評(píng)論 0 8
  • 這篇文章是下篇昌阿,所以如果你對(duì)TCP不熟悉的話,還請(qǐng)你先看看上篇《TCP的那些事兒(上)》 上篇中,我們介紹了TCP...
    愛我你就抱抱我閱讀 592評(píng)論 0 0
  • 原載 2010-11-30 熊弟兄的空間 (73) 人讀經(jīng)“舊約出不了埃及懦冰,新約到不了羅馬灶轰。”人性如此刷钢,需要拯救笋颤;...
    熊弟兄閱讀 4,520評(píng)論 0 1
  • 周六,北極熊一早給我發(fā)信息闯捎,是一張她站在電子體重秤上的照片唉工,一雙憨態(tài)可掬的腳丫中間的數(shù)字是“52”,還有她興奮的語...
    何寧寧閱讀 300評(píng)論 2 7