www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁(yè) > 公眾號(hào)精選 > 小林coding
[導(dǎo)讀]大家好,我是小林。最近有朋友跟我說,他在看面經(jīng)的時(shí)候,到哪都有我的影子。這個(gè)挺讓我意外的,沒想到我的圖解網(wǎng)絡(luò)和圖解系統(tǒng)已經(jīng)慢慢傳開了,形成一定的口碑了。不知道有多少讀者是通過別人文章認(rèn)識(shí)我的,哈哈。這個(gè)事情就說到了,剎個(gè)車。上周有個(gè)讀者問我,這么個(gè)問題:TCP是面向字節(jié)流的協(xié)議,...

大家好,我是小林。最近有朋友跟我說,他在看面經(jīng)的時(shí)候,到哪都有我的影子。

這個(gè)挺讓我意外的,沒想到我的圖解網(wǎng)絡(luò)和圖解系統(tǒng)已經(jīng)慢慢傳開了,形成一定的口碑了。不知道有多少讀者是通過別人文章認(rèn)識(shí)我的,哈哈。這個(gè)事情就說到了,剎個(gè)車。

上周有個(gè)讀者問我,這么個(gè)問題:

TCP 是面向字節(jié)流的協(xié)議,UDP 是面向報(bào)文的協(xié)議?這里的「面向字節(jié)流」和「面向報(bào)文」該如何理解。

這是個(gè)好問題,剛好我的《圖解網(wǎng)絡(luò)》系列里沒有說過這個(gè)事情,這次就來補(bǔ)一補(bǔ)。

如何理解字節(jié)流?

之所以會(huì)說 TCP 是面向字節(jié)流的協(xié)議,UDP 是面向報(bào)文的協(xié)議,是因?yàn)椴僮飨到y(tǒng)對(duì) TCP 和 UDP 協(xié)議的發(fā)送方的機(jī)制不同,也就是問題原因在發(fā)送方。

先來說說為什么 UDP 是面向報(bào)文的協(xié)議?

當(dāng)用戶消息通過 UDP 協(xié)議傳輸時(shí),操作系統(tǒng)不會(huì)對(duì)消息進(jìn)行拆分,在組裝好 UDP 頭部后就交給網(wǎng)絡(luò)層來處理,所以發(fā)出去的 UDP 報(bào)文中的數(shù)據(jù)部分就是完整的用戶消息,也就是每個(gè) UDP 報(bào)文就是一個(gè)用戶消息的邊界,這樣接收方在接收到 UDP 報(bào)文后,讀一個(gè) UDP 報(bào)文就能讀取到完整的用戶消息。

你可能會(huì)問,如果收到了兩個(gè) UDP 報(bào)文,操作系統(tǒng)是怎么區(qū)分開的?

操作系統(tǒng)在收到 UDP 報(bào)文后,會(huì)將其插入到隊(duì)列里,隊(duì)列里的每一個(gè)元素就是一個(gè) UDP 報(bào)文,這樣當(dāng)用戶調(diào)用 recvfrom() 系統(tǒng)調(diào)用讀數(shù)據(jù)的時(shí)候,就會(huì)從隊(duì)列里取出一個(gè)數(shù)據(jù),然后從內(nèi)核里拷貝給用戶緩沖區(qū)。


再來說說為什么 TCP 是面向字節(jié)流的協(xié)議?

當(dāng)用戶消息通過 TCP 協(xié)議傳輸時(shí),消息可能會(huì)被操作系統(tǒng)分組成多個(gè)的 TCP 報(bào)文,也就是一個(gè)完整的用戶消息被拆分成多個(gè) TCP 報(bào)文進(jìn)行傳輸。

這時(shí),接收方的程序如果不知道發(fā)送方發(fā)送的消息的長(zhǎng)度,也就是不知道消息的邊界時(shí),是無(wú)法讀出一個(gè)有效的用戶消息的,因?yàn)橛脩粝⒈徊鸱殖啥鄠€(gè) TCP 報(bào)文后,并不能像 UDP 那樣,一個(gè) UDP 報(bào)文就能代表一個(gè)完整的用戶消息。

舉個(gè)實(shí)際的例子來說明。

發(fā)送方準(zhǔn)備發(fā)送 「Hi.」和「I am Xiaolin」這兩個(gè)消息。

在發(fā)送端,當(dāng)我們調(diào)用 send 函數(shù)完成數(shù)據(jù)“發(fā)送”以后,數(shù)據(jù)并沒有被真正從網(wǎng)絡(luò)上發(fā)送出去,只是從應(yīng)用程序拷貝到了操作系統(tǒng)內(nèi)核協(xié)議棧中。

至于什么時(shí)候真正被發(fā)送,取決于發(fā)送窗口、擁塞窗口以及當(dāng)前發(fā)送緩沖區(qū)的大小等條件。也就是說,我們不能認(rèn)為每次 send 調(diào)用發(fā)送的數(shù)據(jù),都會(huì)作為一個(gè)整體完整地消息被發(fā)送出去。

如果我們考慮實(shí)際網(wǎng)絡(luò)傳輸過程中的各種影響,假設(shè)發(fā)送端陸續(xù)調(diào)用 send 函數(shù)先后發(fā)送 「Hi.」和「I am Xiaolin」 報(bào)文,那么實(shí)際的發(fā)送很有可能是這幾種情況。

第一種情況,這兩個(gè)消息被分到同一個(gè) TCP 報(bào)文,像這樣:

第二種情況,「I am Xiaolin」的部分隨 「Hi」 在一個(gè) TCP 報(bào)文中發(fā)送出去,像這樣:

第三種情況,「Hi.」 的一部分隨 TCP 報(bào)文被發(fā)送出去,另一部分和 「I am Xiaolin」 一起隨另一個(gè) TCP 報(bào)文發(fā)送出去,像這樣。

類似的情況還能舉例很多種,這里主要是想說明,我們不知道 「Hi.」和 「I am Xiaolin」 這兩個(gè)用戶消息是如何進(jìn)行 TCP 分組傳輸?shù)摹?/p>因此,我們不能認(rèn)為一個(gè)用戶消息對(duì)應(yīng)一個(gè) TCP 報(bào)文,正因?yàn)檫@樣,所以 TCP 是面向字節(jié)流的協(xié)議。

當(dāng)兩個(gè)消息的某個(gè)部分內(nèi)容被分到同一個(gè) TCP 報(bào)文時(shí),就是我們常說的 TCP 粘包問題,這時(shí)接收方不知道消息的邊界的話,是無(wú)法讀出有效的消息。

要解決這個(gè)問題,要交給應(yīng)用程序

如何解決粘包?

粘包的問題出現(xiàn)是因?yàn)椴恢酪粋€(gè)用戶消息的邊界在哪,如果知道了邊界在哪,接收方就可以通過邊界來劃分出有效的用戶消息。

一般有三種方式分包的方式:

  • 固定長(zhǎng)度的消息;

  • 特殊字符作為邊界;

  • 自定義消息結(jié)構(gòu)。

固定長(zhǎng)度的消息
這種是最簡(jiǎn)單方法,即每個(gè)用戶消息都是固定長(zhǎng)度的,比如規(guī)定一個(gè)消息的長(zhǎng)度是 64 個(gè)字節(jié),當(dāng)接收方接滿 64 個(gè)字節(jié),就認(rèn)為這個(gè)內(nèi)容是一個(gè)完整且有效的消息。

但是這種方式靈活性不高,實(shí)際中很少用。

特殊字符作為邊界

我們可以在兩個(gè)用戶消息之間插入一個(gè)特殊的字符串,這樣接收方在接收數(shù)據(jù)時(shí),讀到了這個(gè)特殊字符,就把認(rèn)為已經(jīng)讀完一個(gè)完整的消息。

HTTP 是一個(gè)非常好的例子。

HTTP 通過設(shè)置回車符、換行符作為 HTTP 報(bào)文協(xié)議的邊界。

有一點(diǎn)要注意,這個(gè)作為邊界點(diǎn)的特殊字符,如果剛好消息內(nèi)容里有這個(gè)特殊字符,我們要對(duì)這個(gè)字符轉(zhuǎn)義,避免被接收方當(dāng)作消息的邊界點(diǎn)而解析到無(wú)效的數(shù)據(jù)。

自定義消息結(jié)構(gòu)

我們可以自定義一個(gè)消息結(jié)構(gòu),由包頭和數(shù)據(jù)組成,其中包頭包是固定大小的,而且包頭里有一個(gè)字段來說明緊隨其后的數(shù)據(jù)有多大。

比如這個(gè)消息結(jié)構(gòu)體,首先 4 個(gè)字節(jié)大小的變量來表示數(shù)據(jù)長(zhǎng)度,真正的數(shù)據(jù)則在后面。

struct?{?
????u_int32_t?message_length;?
????char?message_data[];?
}?message;
當(dāng)接收方接收到包頭的大小(比如 4 個(gè)字節(jié))后,就解析包頭的內(nèi)容,于是就可以知道數(shù)據(jù)的長(zhǎng)度,然后接下來就繼續(xù)讀取數(shù)據(jù),直到讀滿數(shù)據(jù)的長(zhǎng)度,就可以組裝成一個(gè)完整到用戶消息來處理了。

沒想到吧,又是深夜技術(shù)文

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
關(guān)閉
關(guān)閉