• <dd id="1o0vv"></dd>
    <code id="1o0vv"><label id="1o0vv"></label></code>
  • <center id="1o0vv"></center>
  • 加入星計(jì)劃,您可以享受以下權(quán)益:

    • 創(chuàng)作內(nèi)容快速變現(xiàn)
    • 行業(yè)影響力擴(kuò)散
    • 作品版權(quán)保護(hù)
    • 300W+ 專業(yè)用戶
    • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
    • 5000+ 長期合作伙伴
    立即加入
    • 正文
      • 前言
      • LwIP 的分層機(jī)制
      • UDP 協(xié)議
      • UDP 數(shù)據(jù)結(jié)構(gòu)體解析
      •  
      • 總結(jié)
    • 相關(guān)推薦
    • 電子產(chǎn)業(yè)圖譜
    申請(qǐng)入駐 產(chǎn)業(yè)圖譜

    LwIP 協(xié)議棧之 udp 協(xié)議解析

    2020/12/22
    451
    閱讀需 13 分鐘
    加入交流群
    掃碼加入
    獲取工程師必備禮包
    參與熱點(diǎn)資訊討論

    前言

    之前在做一個(gè)關(guān)于數(shù)據(jù)傳輸的時(shí)候,使用到了 WiFi 傳輸數(shù)據(jù),而在傳輸數(shù)據(jù)時(shí)使用到的協(xié)議就是 LwIP 協(xié)議棧中的 udp 協(xié)議?,F(xiàn)在來回顧總結(jié)一下。要敘述 LwIP 協(xié)議棧,那自然得明白 LwIP 協(xié)議棧具體是個(gè)啥??偟膩碚f,LwIP 是 TCP/IP 協(xié)議中一種獨(dú)立、簡單的實(shí)現(xiàn),其設(shè)計(jì)目的在于保證嵌入式產(chǎn)品擁有完整 TCP/IP 功能的同時(shí),又能夠保證協(xié)議棧對(duì)處理器資源的有效消耗,其運(yùn)行一般僅需要幾十 KB 的 RAM 和 40KB 左右的 ROM。上述所說便是關(guān)于 LwIP 協(xié)議棧的相關(guān)敘述。

    LwIP 的分層機(jī)制

    在敘述 udp 協(xié)議概念之前,先對(duì) LwIP 協(xié)議的框架有一個(gè)簡單的了解,LwIP 在實(shí)現(xiàn)的時(shí)候,參考了 TCP/IP 協(xié)議的分層思想,每一層都在一個(gè)單獨(dú)的模塊中實(shí)現(xiàn),并為其他層次模塊提供一些輸入 / 輸出接口函數(shù)。下面是分層結(jié)構(gòu)示意圖:

    image-20201219165628915

    如同前面所說,LwIP 協(xié)議只是參考了 TCP/IP 的分層結(jié)構(gòu),但是它并沒有嚴(yán)格地遵循上述所示地分層機(jī)制,其為了節(jié)省時(shí)間和空間上地消耗,各個(gè)層次之間存在著交叉存取地現(xiàn)象。

    我們通過上述地框圖可以知道 UDP 屬于傳輸層協(xié)議。要明白為什么有傳輸層協(xié)議,我們需要明白在傳輸層的下一層,也就是網(wǎng)絡(luò)互連層,有 IP 協(xié)議,IP 協(xié)議是用于數(shù)據(jù)報(bào)在各個(gè)主機(jī)中傳遞的,但是我們?cè)趯?shí)際的應(yīng)用過程中,我們所需要的是數(shù)據(jù)報(bào)在各個(gè)應(yīng)用之間傳遞,說白了也就是在進(jìn)程與進(jìn)程之間通信,而傳輸層的存在就是為了實(shí)現(xiàn)數(shù)據(jù)報(bào)在進(jìn)程與進(jìn)程之間通信的。

    而要完成進(jìn)程到進(jìn)程之間的通信,傳輸層需要完成幾個(gè)重要的任務(wù):

    第一:為兩個(gè)通信的進(jìn)程提供連接機(jī)制,也就是說傳輸層在接收了 IP 層傳輸過來的數(shù)據(jù)之后,應(yīng)該將這個(gè)數(shù)據(jù)傳到哪一個(gè)應(yīng)用程序中。在這里是通過端口號(hào)來完成的。

    第二:傳輸層需要提供數(shù)據(jù)傳送服務(wù)。在數(shù)據(jù)發(fā)送端,傳輸層將數(shù)據(jù)進(jìn)行組裝、編號(hào),將數(shù)據(jù)分割成可運(yùn)輸?shù)膯卧?,然后依次遞交給 IP 層發(fā)送出去。而接收端的傳輸層需要等屬于同一應(yīng)用程序的數(shù)據(jù)都到達(dá)之后,對(duì)他們進(jìn)行差錯(cuò)校驗(yàn)、最后將整個(gè)數(shù)據(jù)交付給應(yīng)用程序。

    第三:為了提供更為可靠的傳輸服務(wù),傳輸層還應(yīng)該提供流量控制機(jī)制。

    UDP 協(xié)議

    在簡單地?cái)⑹隽岁P(guān)于 LwIP 的框架之后,接下來詳細(xì)闡述 UDP 地相關(guān)概念。UDP 稱之為用戶數(shù)據(jù)報(bào)協(xié)議,是一種無連接地、不可靠地傳輸協(xié)議,它只在低級(jí)程度上實(shí)現(xiàn)了上述地傳輸層功能,為什么說只在低級(jí)程度上實(shí)現(xiàn)了上述功能呢?因?yàn)樗皇呛唵蔚赝瓿蓴?shù)據(jù)從一個(gè)進(jìn)程到另一個(gè)進(jìn)程地交付,它沒有提供任何流量控制機(jī)制,收到地報(bào)文也沒有確認(rèn),差錯(cuò)控制上,只提供了檢驗(yàn)和計(jì)算,當(dāng)校驗(yàn)和計(jì)算不成功時(shí),它將丟棄掉這個(gè)報(bào)文。

    當(dāng)用戶的進(jìn)程使用 UDP 來傳送數(shù)據(jù)的時(shí)候,會(huì)經(jīng)歷三個(gè)過程

    (1)UDP 協(xié)議會(huì)在數(shù)據(jù)前加上首部組成 UDP 報(bào)文,并交給 IP 協(xié)議來發(fā)送

    (2)IP 層將報(bào)文封裝在 IP 數(shù)據(jù)報(bào)中并交給底層發(fā)送

    (3)底層,IP 數(shù)據(jù)報(bào)被封裝在物理數(shù)據(jù)幀中

    UDP 數(shù)據(jù)的封裝

    在 UDP 的接收端,物理網(wǎng)絡(luò)先接收到數(shù)據(jù)幀,然后逐層將數(shù)據(jù)遞交給上層協(xié)議,每一層都在向上一層去除掉一個(gè)首部。

    ## UDP 報(bào)文格式

    UDP 報(bào)文成為用戶數(shù)據(jù)報(bào),從結(jié)構(gòu)上可以分為兩部分:UDP 首部和 UDP 數(shù)據(jù)區(qū),下面是報(bào)文結(jié)構(gòu)示意圖:

    image-20201219205656710

    UDP 校驗(yàn)和的計(jì)算超過了 UDP 報(bào)文本身,為了計(jì)算校驗(yàn)和,UDP 引入了偽首部的概念,加入了偽首部之后的 UDP 報(bào)文格式如下圖所示:

    image-20201219210404321

    這里需要指出的一點(diǎn)是,偽首部完全是虛擬的,它并不會(huì)和用戶數(shù)據(jù)報(bào)一起被發(fā)送出去,只是在校驗(yàn)和的計(jì)算過程中會(huì)被使用到,偽首部主要來自于運(yùn)載 UDP 報(bào)文的 IP 數(shù)據(jù)報(bào)首部,將源 IP 地址和目的 IP 地址加入到校驗(yàn)和的計(jì)算中可以驗(yàn)證用戶數(shù)據(jù)報(bào)是否已經(jīng)到達(dá)正確的終點(diǎn)。

    UDP 數(shù)據(jù)結(jié)構(gòu)體解析

    報(bào)文首部結(jié)構(gòu)

    先來看下 UDP 數(shù)據(jù)報(bào)首部,代碼如下:

    #define?UDP_HLEN?8
    
    PACK_STRUCT_BEGIN
    struct?udp_hdr?{
    ??PACK_STRUCT_FIELD(u16_t?src);
    ??PACK_STRUCT_FIELD(u16_t?dest);??/*?src/dest?UDP?ports?*/
    ??PACK_STRUCT_FIELD(u16_t?len);
    ??PACK_STRUCT_FIELD(u16_t?chksum);
    }?PACK_STRUCT_STRUCT;
    PACK_STRUCT_END
    

    這個(gè)結(jié)構(gòu)體很簡潔,使用結(jié)構(gòu)體封裝宏定義的每個(gè)字段,還應(yīng)該注意的是四個(gè)字段保存的值應(yīng)該與網(wǎng)絡(luò)字段保持一致。

    udp 控制塊

    控制塊是整個(gè) UDP 中最為核心的東西,用戶使用 UDP 進(jìn)行編程,以及對(duì)于 UDP 報(bào)文的處理,本質(zhì)上都是對(duì) UDP 控制塊進(jìn)行操作。一個(gè) UDP 的控制塊包含 UDP 連接時(shí)需要的所有信息,主要包括:

    端口號(hào)

    目的端口號(hào)

    源 IP 地址

    目的 IP 地址

    總體來說,系統(tǒng)會(huì)為每一個(gè)連接分配一個(gè) UDP 控制塊,然后將他們組織在一個(gè)全局的鏈表上,當(dāng) UDP 收到 IP 層遞交的報(bào)文的時(shí)候,就會(huì)去遍歷這個(gè)鏈表,找出與報(bào)文中首部信息匹配的控制塊,并調(diào)用控制塊中注冊(cè)的函數(shù)最終完成報(bào)文的處理。

    在定義 UDP 控制塊的時(shí)候,會(huì)使用到 IP 的控制塊

    #define?IP_PCB?struct?ip_addr?local_ip;?
    ??struct?ip_addr?remote_ip;?
    ???/*?Socket?options?*/??
    ??u16_t?so_options;??????
    ???/*?Type?Of?Service?*/?
    ??u8_t?tos;??????????????
    ??/*?Time?To?Live?*/?????
    ??u8_t?ttl;??????????????
    

    如上述所示,IP 控制塊的定義是通過一個(gè)宏來實(shí)現(xiàn)的,它包含了本地 IP 地址、遠(yuǎn)端 IP 地址、socket 選項(xiàng)、服務(wù)類型、生存時(shí)間這幾個(gè)字段。有了 UP 控制塊之后,我們?cè)賮砜?UDP 控制塊,下面是 UDP 控制塊的代碼:

    //?定義回調(diào)函數(shù)的類型
    typedef?void?(*udp_recv_fn)(void?*arg,?struct?udp_pcb?*pcb,?struct?pbuf?*p,
    ????ip_addr_t?*addr,?u16_t?port);
    
    //?定義?UDP?控制塊結(jié)構(gòu)體
    struct?udp_pcb?{
    /*?Common?members?of?all?PCB?types?*/
    ??IP_PCB;
    
    /*?Protocol?specific?PCB?members?*/
    
    ??struct?udp_pcb?*next;
    
    ??u8_t?flags;
    ??/**?ports?are?in?host?byte?order?*/
    ??u16_t?local_port,?remote_port;
    
    #if?LWIP_IGMP
    ??/**?outgoing?network?interface?for?multicast?packets?*/
    ??ip_addr_t?multicast_ip;
    #endif?/*?LWIP_IGMP?*/
    
    #if?LWIP_UDPLITE
    ??/**?used?for?UDP_LITE?only?*/
    ??u16_t?chksum_len_rx,?chksum_len_tx;
    #endif?/*?LWIP_UDPLITE?*/
    
    ??/**?receive?callback?function?*/
    ??udp_recv_fn?recv;
    ??/**?user-supplied?argument?for?the?recv?callback?*/
    ??void?*recv_arg;??
    }
    

    UDP 協(xié)議實(shí)現(xiàn)的本質(zhì)就是對(duì)鏈表上各個(gè) UDP 控制塊進(jìn)行操作,再上述所示的結(jié)構(gòu)體中,next 是一個(gè) UDP 控制塊類型的指針,他就是用來構(gòu)成鏈表的。最后,需要注意的一點(diǎn)是,上述控制塊中的最后兩個(gè)字段的是用于用戶和協(xié)議棧內(nèi)核通信的紐帶,反應(yīng)再 udp 協(xié)議里,就是用來執(zhí)行用戶自定義的報(bào)文數(shù)據(jù)處理函數(shù)的。下面是三個(gè)控制塊構(gòu)成的一個(gè)鏈表的一個(gè)示意圖:

    image-20201220141759180

    通過上述示意圖我們可有看到第一個(gè)控制塊和第二個(gè)控制塊中,包含了本地和遠(yuǎn)程的 IP 地址和端口,所以他們處于連接狀態(tài)。第三個(gè)控制塊中,只包含了本地 IP 地址和端口,所以它處于未連接的狀態(tài)。UDP 的的工作流程是什么呢?簡單來說就是如果當(dāng)前 UDP 控制塊收到一個(gè)目的端口為 1234 的數(shù)據(jù)報(bào),那么內(nèi)核就會(huì)從鏈表的起始處開始遍歷整個(gè)鏈表,直到查出具有本地端口號(hào) 1234 的控制塊。當(dāng)找到控制塊之后,控制塊的 recv 字段指向的函數(shù) proc1 會(huì)被調(diào)用以處理報(bào)文數(shù)據(jù)。

    ?

    總結(jié)

    上述就是關(guān)于 LwIP 中 udp 的一個(gè)解析,只是簡單地說明了 UDP 地一個(gè)基本原理,它所涉及地控制塊以及當(dāng) UDP 接收到數(shù)據(jù)報(bào)地時(shí)候,又是一個(gè)怎樣地處理過程。當(dāng)然,除了這些,關(guān)于 UDP 還有很多地內(nèi)容,如何使用 UDP 發(fā)送數(shù)據(jù)和接收數(shù)據(jù)都沒涉及到,關(guān)于 LwIP 內(nèi)核地內(nèi)容也還需要繼續(xù)仔細(xì)研讀。

    相關(guān)推薦

    電子產(chǎn)業(yè)圖譜

    在讀碩士研究生,喜歡鉆研嵌入式相關(guān)技術(shù),熱衷于寫文章分享知識(shí),不定期輸出關(guān)于單片機(jī), RTOS,信號(hào)處理等相關(guān)內(nèi)容