日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當前位置:首頁 > 單片機 > 小林coding
[導讀]為了使得多種設備能通過網(wǎng)絡相互通信,和為了解決各種不同設備在網(wǎng)絡互聯(lián)中的兼容性問題。

大家好,我是小林。

之前寫過一篇:你不好奇 Linux 是如何收發(fā)網(wǎng)絡包的? 文章。

當時有些地方寫的比較籠統(tǒng),然后我「把 Linux 接收+發(fā)送網(wǎng)絡包的流程」這部分內(nèi)容完善了下,現(xiàn)在重新分享給大家。

發(fā)車發(fā)車!

網(wǎng)絡模型

為了使得多種設備能通過網(wǎng)絡相互通信,和為了解決各種不同設備在網(wǎng)絡互聯(lián)中的兼容性問題。

國際標準化組織制定了開放式系統(tǒng)互聯(lián)通信參考模型(Open System Interconnection Reference Model),也就是 OSI 網(wǎng)絡模型。

該模型主要有 7 層,分別是應用層、表示層、會話層、傳輸層、網(wǎng)絡層、數(shù)據(jù)鏈路層以及物理層。

每一層負責的職能都不同,如下:

  • 應用層,負責給應用程序提供統(tǒng)一的接口;
  • 表示層,負責把數(shù)據(jù)轉(zhuǎn)換成兼容另一個系統(tǒng)能識別的格式;
  • 會話層,負責建立、管理和終止表示層實體之間的通信會話;
  • 傳輸層,負責端到端的數(shù)據(jù)傳輸;
  • 網(wǎng)絡層,負責數(shù)據(jù)的路由、轉(zhuǎn)發(fā)、分片;
  • 數(shù)據(jù)鏈路層,負責數(shù)據(jù)的封幀和差錯檢測,以及 MAC 尋址;
  • 物理層,負責在物理網(wǎng)絡中傳輸數(shù)據(jù)幀;

由于 OSI 模型實在太復雜,提出的也只是概念理論上的分層,并沒有提供具體的實現(xiàn)方案。

事實上,我們比較常見,也比較實用的是四層模型,即 TCP/IP 網(wǎng)絡模型,Linux 系統(tǒng)正是按照這套網(wǎng)絡模型來實現(xiàn)網(wǎng)絡協(xié)議棧的。

TCP/IP 網(wǎng)絡模型共有 4 層,分別是應用層、傳輸層、網(wǎng)絡層和網(wǎng)絡接口層,每一層負責的職能如下:

  • 應用層,負責向用戶提供一組應用程序,比如 HTTP、DNS、FTP 等;
  • 傳輸層,負責端到端的通信,比如 TCP、UDP 等;
  • 網(wǎng)絡層,負責網(wǎng)絡包的封裝、分片、路由、轉(zhuǎn)發(fā),比如 IP、ICMP 等;
  • 網(wǎng)絡接口層,負責網(wǎng)絡包在物理網(wǎng)絡中的傳輸,比如網(wǎng)絡包的封幀、 MAC 尋址、差錯檢測,以及通過網(wǎng)卡傳輸網(wǎng)絡幀等;

TCP/IP 網(wǎng)絡模型相比 OSI 網(wǎng)絡模型簡化了不少,也更加易記,它們之間的關(guān)系如下圖:

不過,我們常說的七層和四層負載均衡,是用 OSI 網(wǎng)絡模型來描述的,七層對應的是應用層,四層對應的是傳輸層。


Linux 網(wǎng)絡協(xié)議棧

我們可以把自己的身體比作應用層中的數(shù)據(jù),打底衣服比作傳輸層中的 TCP 頭,外套比作網(wǎng)絡層中 IP 頭,帽子和鞋子分別比作網(wǎng)絡接口層的幀頭和幀尾。

在冬天這個季節(jié),當我們要從家里出去玩的時候,自然要先穿個打底衣服,再套上保暖外套,最后穿上帽子和鞋子才出門,這個過程就好像我們把 TCP 協(xié)議通信的網(wǎng)絡包發(fā)出去的時候,會把應用層的數(shù)據(jù)按照網(wǎng)絡協(xié)議棧層層封裝和處理。

你從下面這張圖可以看到,應用層數(shù)據(jù)在每一層的封裝格式。

其中:

  • 傳輸層,給應用數(shù)據(jù)前面增加了 TCP  頭;
  • 網(wǎng)絡層,給 TCP 數(shù)據(jù)包前面增加了 IP  頭;
  • 網(wǎng)絡接口層,給 IP 數(shù)據(jù)包前后分別增加了幀頭和幀尾;

這些新增的頭部和尾部,都有各自的作用,也都是按照特定的協(xié)議格式填充,這每一層都增加了各自的協(xié)議頭,那自然網(wǎng)絡包的大小就增大了,但物理鏈路并不能傳輸任意大小的數(shù)據(jù)包,所以在以太網(wǎng)中,規(guī)定了最大傳輸單元(MTU)是1500字節(jié),也就是規(guī)定了單次傳輸?shù)淖畲?IP 包大小。

當網(wǎng)絡包超過 MTU 的大小,就會在網(wǎng)絡層分片,以確保分片后的 IP 包不會超過 MTU 大小,如果 MTU 越小,需要的分包就越多,那么網(wǎng)絡吞吐能力就越差,相反的,如果 MTU 越大,需要的分包就越少,那么網(wǎng)絡吞吐能力就越好。

知道了 TCP/IP 網(wǎng)絡模型,以及網(wǎng)絡包的封裝原理后,那么 Linux 網(wǎng)絡協(xié)議棧的樣子,你想必猜到了大概,它其實就類似于 TCP/IP 的四層結(jié)構(gòu):

從上圖的的網(wǎng)絡協(xié)議棧,你可以看到:

  • 應用程序需要通過系統(tǒng)調(diào)用,來跟 Socket 層進行數(shù)據(jù)交互;
  • Socket 層的下面就是傳輸層、網(wǎng)絡層和網(wǎng)絡接口層;
  • 最下面的一層,則是網(wǎng)卡驅(qū)動程序和硬件網(wǎng)卡設備;

Linux 接收網(wǎng)絡包的流程

網(wǎng)卡是計算機里的一個硬件,專門負責接收和發(fā)送網(wǎng)絡包,當網(wǎng)卡接收到一個網(wǎng)絡包后,會通過 DMA 技術(shù),將網(wǎng)絡包寫入到指定的內(nèi)存地址,也就是寫入到 Ring Buffer ,這個是一個環(huán)形緩沖區(qū),接著就會告訴操作系統(tǒng)這個網(wǎng)絡包已經(jīng)到達。

那應該怎么告訴操作系統(tǒng)這個網(wǎng)絡包已經(jīng)到達了呢?

最簡單的一種方式就是觸發(fā)中斷,也就是每當網(wǎng)卡收到一個網(wǎng)絡包,就觸發(fā)一個中斷告訴操作系統(tǒng)。

但是,這存在一個問題,在高性能網(wǎng)絡場景下,網(wǎng)絡包的數(shù)量會非常多,那么就會觸發(fā)非常多的中斷,要知道當 CPU  收到了中斷,就會停下手里的事情,而去處理這些網(wǎng)絡包,處理完畢后,才會回去繼續(xù)其他事情,那么頻繁地觸發(fā)中斷,則會導致 CPU 一直沒完沒了的處理中斷,而導致其他任務可能無法繼續(xù)前進,從而影響系統(tǒng)的整體效率。

所以為了解決頻繁中斷帶來的性能開銷,Linux 內(nèi)核在 2.6 版本中引入了 NAPI 機制,它是混合「中斷和輪詢」的方式來接收網(wǎng)絡包,它的核心概念就是不采用中斷的方式讀取數(shù)據(jù),而是首先采用中斷喚醒數(shù)據(jù)接收的服務程序,然后poll的方法來輪詢數(shù)據(jù)。

因此,當有網(wǎng)絡包到達時,會通過 DMA 技術(shù),將網(wǎng)絡包寫入到指定的內(nèi)存地址,接著網(wǎng)卡向 CPU 發(fā)起硬件中斷,當 CPU 收到硬件中斷請求后,根據(jù)中斷表,調(diào)用已經(jīng)注冊的中斷處理函數(shù)。

硬件中斷處理函數(shù)會做如下的事情:

  • 需要先「暫時屏蔽中斷」,表示已經(jīng)知道內(nèi)存中有數(shù)據(jù)了,告訴網(wǎng)卡下次再收到數(shù)據(jù)包直接寫內(nèi)存就可以了,不要再通知 CPU 了,這樣可以提高效率,避免 CPU 不停的被中斷。
  • 接著,發(fā)起「軟中斷」,然后恢復剛才屏蔽的中斷。

至此,硬件中斷處理函數(shù)的工作就已經(jīng)完成。

硬件中斷處理函數(shù)做的事情很少,主要耗時的工作都交給軟中斷處理函數(shù)了。

軟中斷的處理

內(nèi)核中的 ksoftirqd 線程專門負責軟中斷的處理,當 ksoftirqd 內(nèi)核線程收到軟中斷后,就會來輪詢處理數(shù)據(jù)。

ksoftirqd 線程會從 Ring Buffer 中獲取一個數(shù)據(jù)幀,用 sk_buff 表示,從而可以作為一個網(wǎng)絡包交給網(wǎng)絡協(xié)議棧進行逐層處理。

網(wǎng)絡協(xié)議棧

首先,會先進入到網(wǎng)絡接口層,在這一層會檢查報文的合法性,如果不合法則丟棄,合法則會找出該網(wǎng)絡包的上層協(xié)議的類型,比如是 IPv4,還是 IPv6,接著再去掉幀頭和幀尾,然后交給網(wǎng)絡層。

到了網(wǎng)絡層,則取出 IP 包,判斷網(wǎng)絡包下一步的走向,比如是交給上層處理還是轉(zhuǎn)發(fā)出去。當確認這個網(wǎng)絡包要發(fā)送給本機后,就會從 IP 頭里看看上一層協(xié)議的類型是 TCP 還是 UDP,接著去掉 IP 頭,然后交給傳輸層。

傳輸層取出 TCP 頭或 UDP 頭,根據(jù)四元組「源 IP、源端口、目的 IP、目的端口」 作為標識,找出對應的 Socket,并把數(shù)據(jù)放到 Socket 的接收緩沖區(qū)。

最后,應用層程序調(diào)用 Socket 接口,將內(nèi)核的 Socket 接收緩沖區(qū)的數(shù)據(jù)「拷貝」到應用層的緩沖區(qū),然后喚醒用戶進程。

至此,一個網(wǎng)絡包的接收過程就已經(jīng)結(jié)束了,你也可以從下圖左邊部分看到網(wǎng)絡包接收的流程,右邊部分剛好反過來,它是網(wǎng)絡包發(fā)送的流程。

Linux 發(fā)送網(wǎng)絡包的流程

如上圖的右半部分,發(fā)送網(wǎng)絡包的流程正好和接收流程相反。

首先,應用程序會調(diào)用 Socket 發(fā)送數(shù)據(jù)包的接口,由于這個是系統(tǒng)調(diào)用,所以會從用戶態(tài)陷入到內(nèi)核態(tài)中的 Socket 層,內(nèi)核會申請一個內(nèi)核態(tài)的 sk_buff 內(nèi)存,將用戶待發(fā)送的數(shù)據(jù)拷貝到 sk_buff 內(nèi)存,并將其加入到發(fā)送緩沖區(qū)。

接下來,網(wǎng)絡協(xié)議棧從 Socket 發(fā)送緩沖區(qū)中取出 sk_buff,并按照 TCP/IP 協(xié)議棧從上到下逐層處理。

如果使用的是 TCP 傳輸協(xié)議發(fā)送數(shù)據(jù),那么先拷貝一個新的 sk_buff 副本 ,這是因為 sk_buff 后續(xù)在調(diào)用網(wǎng)絡層,最后到達網(wǎng)卡發(fā)送完成的時候,這個 sk_buff 會被釋放掉。而 TCP 協(xié)議是支持丟失重傳的,在收到對方的 ACK 之前,這個 sk_buff 不能被刪除。所以內(nèi)核的做法就是每次調(diào)用網(wǎng)卡發(fā)送的時候,實際上傳遞出去的是 sk_buff 的一個拷貝,等收到 ACK 再真正刪除。

接著,對 sk_buff 填充 TCP 頭。這里提一下,sk_buff 可以表示各個層的數(shù)據(jù)包,在應用層數(shù)據(jù)包叫 data,在 TCP 層我們稱為 segment,在 IP 層我們叫 packet,在數(shù)據(jù)鏈路層稱為 frame。

你可能會好奇,為什么全部數(shù)據(jù)包只用一個結(jié)構(gòu)體來描述呢?協(xié)議棧采用的是分層結(jié)構(gòu),上層向下層傳遞數(shù)據(jù)時需要增加包頭,下層向上層數(shù)據(jù)時又需要去掉包頭,如果每一層都用一個結(jié)構(gòu)體,那在層之間傳遞數(shù)據(jù)的時候,就要發(fā)生多次拷貝,這將大大降低 CPU 效率。

于是,為了在層級之間傳遞數(shù)據(jù)時,不發(fā)生拷貝,只用 sk_buff 一個結(jié)構(gòu)體來描述所有的網(wǎng)絡包,那它是如何做到的呢?是通過調(diào)整 sk_buff 中data的指針,比如:

  • 當接收報文時,從網(wǎng)卡驅(qū)動開始,通過協(xié)議棧層層往上傳送數(shù)據(jù)報,通過增加 skb->data 的值,來逐步剝離協(xié)議首部。
  • 當要發(fā)送報文時,創(chuàng)建 sk_buff 結(jié)構(gòu)體,數(shù)據(jù)緩存區(qū)的頭部預留足夠的空間,用來填充各層首部,在經(jīng)過各下層協(xié)議時,通過減少 skb->data 的值來增加協(xié)議首部。

你可以從下面這張圖看到,當發(fā)送報文時,data 指針的移動過程。

至此,傳輸層的工作也就都完成了。

然后交給網(wǎng)絡層,在網(wǎng)絡層里會做這些工作:選取路由(確認下一跳的 IP)、填充 IP 頭、netfilter 過濾、對超過 MTU 大小的數(shù)據(jù)包進行分片。處理完這些工作后會交給網(wǎng)絡接口層處理。

網(wǎng)絡接口層會通過 ARP 協(xié)議獲得下一跳的 MAC 地址,然后對 sk_buff 填充幀頭和幀尾,接著將 sk_buff 放到網(wǎng)卡的發(fā)送隊列中。

這一些工作準備好后,會觸發(fā)「軟中斷」告訴網(wǎng)卡驅(qū)動程序,這里有新的網(wǎng)絡包需要發(fā)送,驅(qū)動程序會從發(fā)送隊列中讀取 sk_buff,將這個 sk_buff 掛到 RingBuffer 中,接著將 sk_buff 數(shù)據(jù)映射到網(wǎng)卡可訪問的內(nèi)存 DMA 區(qū)域,最后觸發(fā)真實的發(fā)送。

當數(shù)據(jù)發(fā)送完成以后,其實工作并沒有結(jié)束,因為內(nèi)存還沒有清理。當發(fā)送完成的時候,網(wǎng)卡設備會觸發(fā)一個硬中斷來釋放內(nèi)存,主要是釋放 sk_buff 內(nèi)存和清理  RingBuffer 內(nèi)存。

最后,當收到這個 TCP 報文的 ACK 應答時,傳輸層就會釋放原始的 sk_buff 。

發(fā)送網(wǎng)絡數(shù)據(jù)的時候,涉及幾次內(nèi)存拷貝操作?

第一次,調(diào)用發(fā)送數(shù)據(jù)的系統(tǒng)調(diào)用的時候,內(nèi)核會申請一個內(nèi)核態(tài)的 sk_buff 內(nèi)存,將用戶待發(fā)送的數(shù)據(jù)拷貝到 sk_buff 內(nèi)存,并將其加入到發(fā)送緩沖區(qū)。

第二次,在使用 TCP 傳輸協(xié)議的情況下,從傳輸層進入網(wǎng)絡層的時候,每一個 sk_buff 都會被克隆一個新的副本出來。副本 sk_buff 會被送往網(wǎng)絡層,等它發(fā)送完的時候就會釋放掉,然后原始的 sk_buff 還保留在傳輸層,目的是為了實現(xiàn) TCP 的可靠傳輸,等收到這個數(shù)據(jù)包的 ACK 時,才會釋放原始的 sk_buff 。

第三次,當 IP 層發(fā)現(xiàn) sk_buff 大于 MTU 時才需要進行。會再申請額外的 sk_buff,并將原來的 sk_buff 拷貝為多個小的 sk_buff。

總結(jié)

電腦與電腦之間通常都是通過話網(wǎng)卡、交換機、路由器等網(wǎng)絡設備連接到一起,那由于網(wǎng)絡設備的異構(gòu)性,國際標準化組織定義了一個七層的 OSI 網(wǎng)絡模型,但是這個模型由于比較復雜,實際應用中并沒有采用,而是采用了更為簡化的 TCP/IP 模型,Linux 網(wǎng)絡協(xié)議棧就是按照了該模型來實現(xiàn)的。

TCP/IP 模型主要分為應用層、傳輸層、網(wǎng)絡層、網(wǎng)絡接口層四層,每一層負責的職責都不同,這也是 Linux 網(wǎng)絡協(xié)議棧主要構(gòu)成部分。

當應用程序通過 Socket 接口發(fā)送數(shù)據(jù)包,數(shù)據(jù)包會被網(wǎng)絡協(xié)議棧從上到下進行逐層處理后,才會被送到網(wǎng)卡隊列中,隨后由網(wǎng)卡將網(wǎng)絡包發(fā)送出去。

而在接收網(wǎng)絡包時,同樣也要先經(jīng)過網(wǎng)絡協(xié)議棧從下到上的逐層處理,最后才會被送到應用程序。

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

LED驅(qū)動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: 驅(qū)動電源

在工業(yè)自動化蓬勃發(fā)展的當下,工業(yè)電機作為核心動力設備,其驅(qū)動電源的性能直接關(guān)系到整個系統(tǒng)的穩(wěn)定性和可靠性。其中,反電動勢抑制與過流保護是驅(qū)動電源設計中至關(guān)重要的兩個環(huán)節(jié),集成化方案的設計成為提升電機驅(qū)動性能的關(guān)鍵。

關(guān)鍵字: 工業(yè)電機 驅(qū)動電源

LED 驅(qū)動電源作為 LED 照明系統(tǒng)的 “心臟”,其穩(wěn)定性直接決定了整個照明設備的使用壽命。然而,在實際應用中,LED 驅(qū)動電源易損壞的問題卻十分常見,不僅增加了維護成本,還影響了用戶體驗。要解決這一問題,需從設計、生...

關(guān)鍵字: 驅(qū)動電源 照明系統(tǒng) 散熱

根據(jù)LED驅(qū)動電源的公式,電感內(nèi)電流波動大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

關(guān)鍵字: LED 設計 驅(qū)動電源

電動汽車(EV)作為新能源汽車的重要代表,正逐漸成為全球汽車產(chǎn)業(yè)的重要發(fā)展方向。電動汽車的核心技術(shù)之一是電機驅(qū)動控制系統(tǒng),而絕緣柵雙極型晶體管(IGBT)作為電機驅(qū)動系統(tǒng)中的關(guān)鍵元件,其性能直接影響到電動汽車的動力性能和...

關(guān)鍵字: 電動汽車 新能源 驅(qū)動電源

在現(xiàn)代城市建設中,街道及停車場照明作為基礎設施的重要組成部分,其質(zhì)量和效率直接關(guān)系到城市的公共安全、居民生活質(zhì)量和能源利用效率。隨著科技的進步,高亮度白光發(fā)光二極管(LED)因其獨特的優(yōu)勢逐漸取代傳統(tǒng)光源,成為大功率區(qū)域...

關(guān)鍵字: 發(fā)光二極管 驅(qū)動電源 LED

LED通用照明設計工程師會遇到許多挑戰(zhàn),如功率密度、功率因數(shù)校正(PFC)、空間受限和可靠性等。

關(guān)鍵字: LED 驅(qū)動電源 功率因數(shù)校正

在LED照明技術(shù)日益普及的今天,LED驅(qū)動電源的電磁干擾(EMI)問題成為了一個不可忽視的挑戰(zhàn)。電磁干擾不僅會影響LED燈具的正常工作,還可能對周圍電子設備造成不利影響,甚至引發(fā)系統(tǒng)故障。因此,采取有效的硬件措施來解決L...

關(guān)鍵字: LED照明技術(shù) 電磁干擾 驅(qū)動電源

開關(guān)電源具有效率高的特性,而且開關(guān)電源的變壓器體積比串聯(lián)穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機重量也有所下降,所以,現(xiàn)在的LED驅(qū)動電源

關(guān)鍵字: LED 驅(qū)動電源 開關(guān)電源

LED驅(qū)動電源是把電源供應轉(zhuǎn)換為特定的電壓電流以驅(qū)動LED發(fā)光的電壓轉(zhuǎn)換器,通常情況下:LED驅(qū)動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: LED 隧道燈 驅(qū)動電源
關(guān)閉