linux 服務(wù)器收到網(wǎng)絡(luò)數(shù)據(jù)包,需求經(jīng)過(guò)哪些處置,一步步將數(shù)據(jù)傳給應(yīng)用進(jìn)程的呢?應(yīng)用進(jìn)程發(fā)送數(shù)據(jù)包時(shí),Linux 又是如何操作將數(shù)據(jù)包發(fā)送進(jìn)來(lái)的呢?今天我們就來(lái)聊聊這個(gè)話題。
在準(zhǔn)備好接納網(wǎng)絡(luò)數(shù)據(jù)包之前,Linux需求做很多準(zhǔn)備工作,例如:網(wǎng)絡(luò)子系統(tǒng)的初始化、協(xié)議棧的注冊(cè)、網(wǎng)卡驅(qū)動(dòng)的初始化、啟動(dòng)網(wǎng)卡等等,只要這些都準(zhǔn)備好了之后,才敢真正開(kāi)端接納網(wǎng)絡(luò)包。
網(wǎng)絡(luò)協(xié)議棧
在引見(jiàn)Linux收發(fā)網(wǎng)絡(luò)數(shù)據(jù)包之前,我們先來(lái)理解一下Linux網(wǎng)絡(luò)協(xié)議棧。
國(guó)際規(guī)范化組織制定了開(kāi)放式系統(tǒng)互聯(lián)通訊參考模型(Open System Interconnection Reference Model),也就是 OSI 網(wǎng)絡(luò)模型,該模型主要有 7 層,分別是應(yīng)用層、表示層、會(huì)話層、傳輸層、網(wǎng)絡(luò)層、數(shù)據(jù)鏈路層以及物理層。
由于 OSI 模型太復(fù)雜,提出的只是存在于概念和理論上的一種模型,分層太多,增加了網(wǎng)絡(luò)工作的復(fù)雜性,所以沒(méi)有大范圍應(yīng)用。
我們比擬常見(jiàn)是TCP/IP 網(wǎng)絡(luò)模型,Linux 系統(tǒng)正是依照這套網(wǎng)絡(luò)模型來(lái)完成網(wǎng)絡(luò)協(xié)議棧的。
TCP/IP 網(wǎng)絡(luò)模型共有 4 層,分別是應(yīng)用層、傳輸層、網(wǎng)絡(luò)層和網(wǎng)絡(luò)接口層,每一層擔(dān)任的職能如下:
1、應(yīng)用層 對(duì)應(yīng)于OSI參考模型的高層,為用戶提供所需求的各種效勞,例如:FTP、Te.NET、DNS、SMTP等.
2、傳輸層 對(duì)應(yīng)于OSI參考模型的傳輸層,為應(yīng)用層實(shí)體提供端到端的通訊功用,保證了數(shù)據(jù)包的次第傳送及數(shù)據(jù)的完好性。該層定義了兩個(gè)主要的協(xié)議:傳輸控制協(xié)議(TCP)和用戶數(shù)據(jù)報(bào)協(xié)議(UDP).
3、網(wǎng)絡(luò)層 對(duì)應(yīng)于OSI參考模型的網(wǎng)絡(luò)層,主要處理主機(jī)到主機(jī)的通訊問(wèn)題。它所包含的協(xié)議設(shè)計(jì)數(shù)據(jù)包在整個(gè)網(wǎng)絡(luò)上的邏輯傳輸。注重重新賦予主機(jī)一個(gè)IP地址來(lái)完成對(duì)主機(jī)的尋址,它還擔(dān)任數(shù)據(jù)包在多種網(wǎng)絡(luò)中的路由。該層有三個(gè)主要協(xié)議:網(wǎng)際協(xié)議(IP)、互聯(lián)網(wǎng)組管理協(xié)議(IGMP)和互聯(lián)網(wǎng)控制報(bào)文協(xié)議(ICMP)。
4、網(wǎng)絡(luò)接口層 與OSI參考模型中的物理層和數(shù)據(jù)鏈路層相對(duì)應(yīng)。它擔(dān)任監(jiān)視數(shù)據(jù)在主機(jī)和網(wǎng)絡(luò)之間的交流。事實(shí)上,TCP/IP自身并未定義該層的協(xié)議,而由參與互連的各網(wǎng)絡(luò)運(yùn)用本人的物理層和數(shù)據(jù)鏈路層協(xié)議,然后與TCP/IP的網(wǎng)絡(luò)接入層停止銜接。地址解析協(xié)議(ARP)工作在此層,即OSI參考模型的數(shù)據(jù)鏈路層。
接納網(wǎng)絡(luò)數(shù)據(jù)包
網(wǎng)絡(luò)數(shù)據(jù)包抵達(dá)網(wǎng)卡后,依照FIFO次第被存入網(wǎng)卡的接納隊(duì)列,網(wǎng)卡經(jīng)過(guò) DMA 技術(shù),將網(wǎng)絡(luò)包寫(xiě)入到指定的內(nèi)存地址(Ring Buffer)。
Ring Buffer是在網(wǎng)卡驅(qū)動(dòng)程序啟動(dòng)時(shí)創(chuàng)立和初始化的,存儲(chǔ)的是sk_buff緩沖區(qū)的描繪符(物理地址和大小等)。
當(dāng)網(wǎng)絡(luò)包抵達(dá)時(shí),從Ring Buffer獲取指向的sk_buff描繪符,經(jīng)過(guò)DMA將數(shù)據(jù)寫(xiě)入該地址。等sk_buff中的數(shù)據(jù)交由上層協(xié)議棧處置后,Ring Buffer中的描繪更新為新分配的sk_buff。
接著網(wǎng)卡向 CPU 發(fā)起硬件中綴,當(dāng) CPU 收到硬件中綴懇求后,依據(jù)中綴注冊(cè)表,找到注冊(cè)的中綴處置函數(shù)。
硬件中綴處置函數(shù)會(huì)做如下的事情:
1、屏蔽網(wǎng)卡的中綴
目的是防止CPU被頻繁中綴而無(wú)法處置其他任務(wù),屏蔽中綴是通知網(wǎng)卡曾經(jīng)曉得內(nèi)存中有數(shù)據(jù)了,下次再收到數(shù)據(jù)包直接寫(xiě)內(nèi)存就能夠了,不要再通知 CPU 了。
2、發(fā)起軟中綴,恢復(fù)方才屏蔽的中綴
內(nèi)核中的 ksoftirqd 線程收到軟中綴后,就會(huì)調(diào)用相應(yīng)軟中綴的處置函數(shù)來(lái)輪詢處置數(shù)據(jù),即:從Ring Buffer 中獲取一個(gè)數(shù)據(jù)幀,用 sk_buff 表示,作為一個(gè)網(wǎng)絡(luò)包交給網(wǎng)絡(luò)協(xié)議棧從下到上停止逐層處置。
網(wǎng)絡(luò)協(xié)議棧對(duì)網(wǎng)絡(luò)包的處置流程如下:
1、網(wǎng)絡(luò)接口層
首先,網(wǎng)絡(luò)接口層檢查報(bào)文的合法性和正確性,假如不合法或報(bào)文校驗(yàn)不正確則丟棄,否則找出上層協(xié)議的類型(IPv4還是IPv6),去掉幀頭、幀尾,然后交給上層即網(wǎng)絡(luò)層處置。
2、網(wǎng)絡(luò)層
網(wǎng)絡(luò)層取出IP頭,判別網(wǎng)絡(luò)包下一步的走向,是轉(zhuǎn)發(fā)還是交給上層。當(dāng)確認(rèn)網(wǎng)絡(luò)包是要發(fā)送給本機(jī)后,就取出上層協(xié)議的類型(比方TCP或UDP),去掉IP頭,然后交給傳輸層處置。
3、傳輸層
傳輸層取出 TCP 頭或者 UDP 頭后,依據(jù)四元組【 源 IP、源端口、目的 IP、目的端口 】,找出對(duì)應(yīng)的 Socket,并把數(shù)據(jù)拷貝到 Socket 的接納緩沖區(qū)。
4、應(yīng)用層
最后,應(yīng)用層程序調(diào)用 Socket 接口,將內(nèi)核的 Socket 接納緩沖區(qū)的數(shù)據(jù)拷貝到應(yīng)用層的緩沖區(qū)。
到這里,一個(gè)網(wǎng)絡(luò)包的接納過(guò)程就完畢了。
發(fā)送網(wǎng)絡(luò)數(shù)據(jù)包
我們理解了網(wǎng)絡(luò)包的接納流程后,就很容易了解網(wǎng)絡(luò)包的發(fā)送流程了。網(wǎng)絡(luò)包的發(fā)送方向,正好跟接納方向相反。
首先,應(yīng)用程序調(diào)用 Socket 發(fā)送網(wǎng)絡(luò)包的接口。這是一個(gè)系統(tǒng)調(diào)用,會(huì)從用戶態(tài)墮入到內(nèi)核態(tài)的套接字層中。
套接字層會(huì)申請(qǐng)一個(gè)內(nèi)核態(tài)的 sk_buff 內(nèi)存,將用戶待發(fā)送的數(shù)據(jù)拷貝到 sk_buff 內(nèi)存,并將其參加到Socket發(fā)送緩沖區(qū)等候網(wǎng)絡(luò)協(xié)議棧的處置。
由于網(wǎng)絡(luò)數(shù)據(jù)包從應(yīng)用程序傳到內(nèi)核時(shí)是原始數(shù)據(jù),協(xié)議棧要在原始數(shù)據(jù)中參加通訊商定才干保證數(shù)據(jù)抵達(dá)效勞端能被正確辨認(rèn)。網(wǎng)絡(luò)協(xié)議棧從 Socket 發(fā)送緩沖區(qū)中,取出數(shù)據(jù)包,然后依照 TCP/IP 棧的分層(傳輸層、網(wǎng)絡(luò)層、網(wǎng)絡(luò)接口層),從上到下逐層停止處置,各層將協(xié)議的頭信息不時(shí)插入到數(shù)據(jù)包中。
協(xié)議棧對(duì)發(fā)送數(shù)據(jù)包的處置流程如下:
1、傳輸層
在傳輸層,會(huì)為器添加TCP頭,同時(shí)拷貝一個(gè)新的 sk_buff 副本 ,這是由于 sk_buff 在抵達(dá)網(wǎng)卡發(fā)送完成的時(shí)分,會(huì)被釋放掉,而TCP 協(xié)議是支持重傳的,為確保網(wǎng)絡(luò)包牢靠傳輸,在收到對(duì)方的 ACK 之前,這個(gè) sk_buff 不能被刪除。
2、網(wǎng)絡(luò)層
在網(wǎng)絡(luò)層,主要會(huì)做這些工作:選取路由(確認(rèn)下一跳的 IP)、填充 IP 頭、netfilter 過(guò)濾、對(duì)超越 MTU 大小的數(shù)據(jù)包停止分片。處置完這些工作后會(huì)交給網(wǎng)絡(luò)接口層處置。
3、網(wǎng)絡(luò)接口層
網(wǎng)絡(luò)接口層會(huì)停止物理地址尋址,以找到下一跳的 mac 地址,填充幀頭和幀尾,將其放到發(fā)送隊(duì)列中。然后觸發(fā)軟中綴通知網(wǎng)卡驅(qū)動(dòng)程序:隊(duì)列中有新的網(wǎng)絡(luò)包需求發(fā)送。驅(qū)動(dòng)程序收到通知會(huì)經(jīng)過(guò) DMA ,從發(fā)送包隊(duì)列中讀出網(wǎng)絡(luò)幀,并經(jīng)過(guò)DMA將數(shù)據(jù)寫(xiě)入網(wǎng)卡的FIFO發(fā)送隊(duì)列。
4、網(wǎng)卡設(shè)備
網(wǎng)卡設(shè)備從FIFO發(fā)送隊(duì)列中取出數(shù)據(jù)包,將其發(fā)送到網(wǎng)絡(luò);當(dāng)發(fā)送完成的時(shí)分,網(wǎng)卡設(shè)備會(huì)觸發(fā)一個(gè)硬中綴來(lái)釋放內(nèi)存,主要是釋放 sk_buff內(nèi)存和清算 RingBuffer 內(nèi)存。最后,當(dāng)收到這個(gè) TCP 報(bào)文的 ACK 應(yīng)對(duì)時(shí),傳輸層就會(huì)釋放原始的 sk_buff。
至此,一個(gè)網(wǎng)絡(luò)包的發(fā)送流程就完畢了。
來(lái)源: 碼農(nóng)猿星球