按照上一小節的介紹,我們下載兩個包:lwip-2.1.2.zip(源碼包)和contrib-2.1.0.zip(contrib包)。解壓以后會得到兩個文件夾,如圖 2?4所示。

我們先打開“lwip-2.1.2”文件夾,如圖 2?5所示。

該目錄的內容為:
* (1)CHANGELOG文件記錄了LwIP在版本升級過程中源代碼發生的變化。
* (2)COPYING文件記錄了LwIP這個開源軟件的license。一個軟件開源,不代表你能無限制地使用它,你需要在使用它的過程中遵守一定的規則,這些規則就是license。大家可以用記事本打開這個COPYING文件看看它的內容。開源軟件的license有很多種,LwIP的屬于BSD License。LwIP的開源程度是很高的,你幾乎可以無限制地使用它。
* (3)FILES文件用于介紹當前目錄下的目錄信息。
* (4)README文件對LwIP進行了一個簡單的介紹。
* (5)UPGRADING文件記錄了LwIP每個大版本的更新,會對用戶使用和移植LwIP造成的影響。所謂大版本更新指的是:1.3.x - 1.4.x – 2.0.x – 2.1.x。小版本更新,比如2.0.1 – 2.0.2 – 2.0.3,這個過程只是一些bug的修復和性能的改善,不會對用戶的使用造成影響。用戶只要將原有工程的目錄中與LwIP相關的舊版本文件替換成新版本的文件,重新編譯,就能直接使用。
* (6)doc文件夾里面是關于LwIP的一些文檔,可以看成是應用和移植LwIP的指南。但是這些文檔比較零散,不成體系,而且純文本閱讀起來很費勁,閱讀意義不是很大。
* (7)test文件夾里面是測試LwIP內核性能的源碼,將它們和LwIP源碼加入到工程中一起編譯,調用它們提供的函數,可以獲得許多與LwIP內核性能有關的指標。這種內核性能測試功能,只有非常專業的人士才用的到。
* (8)src文件夾里面就是我們最關心的LwIP源碼文件,下面會詳細講解。
打開src文件夾,如圖 2?6所示。

* api文件夾里面裝的是NETCONN API和Socket API相關的源文件,只有在操作系統的環境中,才能被編譯。
* apps文件夾里面裝的是應用程序的源文件,包括常見的應用程序,如httpd、mqtt、tftp、sntp、snmp等。
* core文件夾里面是LwIP的內核源文件,后續會詳細講解。
* include文件夾里面是LwIP所有模塊對應的頭文件。
* netif文件夾里面是與網卡移植有關的文件,這些文件為我們移植網卡提供了模板,我們可以直接使用。
LwIP內核是由一系列模塊組合而成的,這些模塊包括:TCP/IP協議棧的各種協議、內存管理模塊、數據包管理模塊、網卡管理模塊、網卡接口模塊、基礎功能類模塊、API模塊。每個模塊是由相關的幾個源文件和頭文件組成的,通過頭文件對外聲明一些函數、宏、數據類型,使得其它模塊可以方便地調用此模塊的功能。而構成每個模塊的頭文件都被組織在了include目錄中,而源文件則根據類型被分散地組織在api、apps、core、netif目錄中。
接下來,我們介紹一下core文件夾,如圖 2?7所示。

我們逐一介紹一下這些源文件的功能。
* ipv4文件夾里面是與IPv4模塊相關的源文件,它們實現了IPv4協議規定的對數據包的各種操作。ipv4文件夾中還包括一些并非屬于IP協議,但會受IP協議影響的協議源文件,包括DHCP、ARP、ICMP、IGMP。
* ipv6文件夾里面是與IPv6模塊相關的源文件,它們實現了IPv6協議規定的對數據包的各種操作。ipv6文件夾中還包括一些并非屬于IP協議,但會受IP協議影響的協議源文件,包括DHCP、ARP、ICMP、IGMP。
* altcp.c、altcp\_alloc.c、altcp\_tcp.c等文件是應用程序分層TCP連接API,從TCPIP線程使用,是一個抽象層,可以模擬應用程序的tcp回調API,同時防止直接鏈接,這樣,應用程序可以使用其他應用程序層協議在TCP之上而不知道細節(例如TLS,代理連接),此類接口我們并沒有怎么使用。
* def.c文件定義了一些基礎類函數,比如主機序和網絡序的轉換、字符串的查找和比較、整數轉換成字符串等,這些函數會被LwIP內核的很多模塊所調用。在include目錄里面的def.h文件對外聲明了def.c所實現的函數,同時定義了許多宏,能實現一些基礎操作,比如取最大值、取最小值、計算數組長度等,這些宏同樣也被內核的許多模塊所調用。我們經常可以看到某個內核的源文件在開始的地方#include “def.h”。
* dns.c文件實現了域名解析的功能,有了它,用戶就可以在知道服務器域名的情況下,獲得該服務器的IP地址。很多時候我們只記得服務器域名而不記得服務器IP地址,例如“www.baidu.com”就是一個域名,通過dns功能,我們就可以得到與服務器域名對應的IP地址,這給用戶使用帶來很大的方便。
* inet\_chksum.c文件提供了LwIP所需的校驗和功能,在IP、UDP、TCP協議的實現中,需要計算校驗和。
* init.c文件對LwIP的用戶宏配置進行了檢查,會將配置錯誤和不合理的地方,通過編譯器的#error和#warning功能表示出來。另外,init.c定義了lwip\_init初始化函數,這個函數會依次對LwIP的各個模塊進行初始化。
* ip.c文件實現了IP協議相關的函數,但只是封裝了ipv4和ipv6文件夾中的函數。
* mem.c文件實現了動態內存池管理機制,使得LwIP內核的各個模塊可以靈活地申請和釋放內存。
* memp.c文件實現了靜態內存堆管理機制,使得LwIP內核的各個模塊可以快速地申請和釋放內存。
* netif.c文件實現了網卡的操作,比如注冊/刪除網卡、使能/禁能網卡、設置網卡IP地址等等。netif.c與include目錄中的netif.h文件共同構成了LwIP的netif模塊,它對網卡進行了抽象,使得LwIP內核可以方便地管理多個特性各異的物理網卡。
* pbuf.c文件實現了LwIP對網絡數據包的各種操作。網絡數據包在LwIP內核中以pbuf結構體的形式存在,這提高了LwIP內核對數據包處理效率,以及提高了數據包在各層之間遞交的效率。pbuf結構體也是我們使用RAW/Callback API進行網絡應用程序開發的關鍵,后續我們會詳細講解。
* raw.c文件實現了一個傳輸層協議的框架,我們可以在它的基礎上修改和添加代碼,實現自定義的傳輸層協議,與UDP/TCP一樣,它可以與IP層直接進行交互。這類似RAW Socket。在實際的應用中,我們常用UDP和TCP作為傳輸層協議。但有時,底層網絡開發人員會嫌UDP的可靠性太差,或者TCP雖然可靠性強,但是很耗費時間和內存,他們需要根據實際需求,平衡利弊,定義自己的傳輸層協議。LwIP的raw模塊可以滿足他們的需求。
* stat.c文件實現了LwIP內核的統計功能,使用戶可以實時地查看LwIP內核對網絡數據包的處理情況。
* sys.c文件和sys.h文件構成了LwIP的sys模塊,它提供了與臨界區相關的操作。
* tcp.c、tcp\_in.c和tcp\_out.c文件實現了TCP協議,包括對TCP連接的操作、對TCP數據包的輸入輸出操作和TCP定時器,它們和include目錄中名稱帶tcp的頭文件共同構成了LwIP的TCP模塊。TCP模塊的實現是LwIP的最大特點,它以很小的資源開銷幾乎實現了TCP協議中規定的全部內容。TCP協議是非常復雜的協議,這幾個與TCP模塊相關的文件占據了LwIP內核的絕大部分。
* timeouts.c定義了LwIP內核的超時處理機制。LwIP內核中多個模塊的實現需要借助超時處理機制,包括ARP表項的時間統計、IP分片報文的重裝、TCP的各種定時器、實現各種應用層協議需要的超時處理。
* udp.c文件實現了UDP協議,包括對UDP連接的操作和UDP數據包的操作。
- 說明
- 第1章:網絡協議簡介
- 1.1:常用網絡協議
- 1.2:網絡協議的分層模型
- 1.3:協議層報文間的封裝與拆封
- 第2章:LwIP簡介
- 2.1:LwIP的優缺點
- 2.2:LwIP的文件說明
- 2.2.1:如何獲取LwIP源碼文件
- 2.2.2:LwIP文件說明
- 2.3:查看LwIP的說明文檔
- 2.4:使用vscode查看源碼
- 2.4.1:查看文件中的符號列表(函數列表)
- 2.4.2:函數定義跳轉
- 2.5:LwIP源碼里的example
- 2.6:LwIP的三種編程接口
- 2.6.1:RAW/Callback API
- 2.6.2:NETCONN API
- 2.6.3:SOCKET API
- 第3章:開發平臺介紹
- 3.1:以太網簡介
- 3.1.1:PHY層
- 3.1.2:MAC子層
- 3.2:STM32的ETH外設
- 3.3:MII 和 RMII 接口
- 3.4:PHY:LAN8720A
- 3.5:硬件設計
- 3.6:軟件設計
- 3.6.1:獲取STM32的裸機工程模板
- 3.6.2:添加bsp_eth.c與bsp_eth.h
- 3.6.3:修改stm32f4xx_hal_conf.h文件
- 第4章:LwIP的網絡接口管理
- 4.1:netif結構體
- 4.2:netif使用
- 4.3:與netif相關的底層函數
- 4.4:ethernetif.c文件內容
- 4.4.1:ethernetif數據結構
- 4.4.2:ethernetif_init()
- 4.4.3:low_level_init()
- 第5章:LwIP的內存管理
- 5.1:幾種內存分配策略
- 5.1.1:固定大小的內存塊
- 5.1.2:可變長度分配
- 5.2:動態內存池(POOL)
- 5.2.1:內存池的預處理
- 5.2.2:內存池的初始化
- 5.2.3:內存分配
- 5.2.4:內存釋放
- 5.3:動態內存堆
- 5.3.1:內存堆的組織結構
- 5.3.2:內存堆初始化
- 5.3.3:內存分配
- 5.3.4:內存釋放
- 5.4:使用C庫的malloc和free來管理內存
- 5.5:LwIP中的配置
- 第6章:網絡數據包
- 6.1:TCP/IP協議的分層思想
- 6.2:LwIP的線程模型
- 6.3:pbuf結構體說明
- 6.4:pbuf的類型
- 6.4.1:PBUF_RAM類型的pbuf
- 6.4.2:PBUF_POOL類型的pbuf
- 6.4.3:PBUF_ROM和PBUF_REF類型pbuf
- 6.5:pbuf_alloc()
- 6.6:pbuf_free()
- 6.7:其它pbuf操作函數
- 6.7.1:pbuf_realloc()
- 6.7.2:pbuf_header()
- 6.7.3:pbuf_take()
- 6.8:網卡中使用的pbuf
- 6.8.1:low_level_output()
- 6.8.2:low_level_input()
- 6.8.3:ethernetif_input()
- 第7章:無操作系統移植LwIP
- 7.1:將LwIP添加到裸機工程
- 7.2:移植頭文件
- 7.3:移植網卡驅動
- 7.4:LwIP時基
- 7.5:協議棧初始化
- 7.6:獲取數據包
- 7.6.1:查詢方式
- 7.6.2:ping命令詳解
- 7.6.3:中斷方式
- 第8章:有操作系統移植LwIP
- 8.1:LwIP中添加操作系統
- 8.1.1:拷貝FreeRTOS源碼到工程文件夾
- 8.1.2:添加FreeRTOS源碼到工程組文件夾
- 8.1.3:指定FreeRTOS頭文件的路徑
- 8.1.4:修改stm32f10x_it.c
- 8.2:lwipopts.h文件需要加入的配置
- 8.3:sys_arch.c/h文件的編寫
- 8.4:網卡底層的編寫
- 8.5:協議棧初始化
- 8.6:移植后使用ping測試基本響應
- 第9章:LwIP一探究竟
- 9.1:網卡接收數據的流程
- 9.2:內核超時處理
- 9.2.1:sys_timeo結構體與超時鏈表
- 9.2.2:注冊超時事件
- 9.2.3:超時檢查
- 9.3:tcpip_thread線程
- 9.4:LwIP中的消息
- 9.4.1:消息結構
- 9.4.2:數據包消息
- 9.4.3:API消息
- 9.5:揭開LwIP神秘的面紗
- 第10章:ARP協議
- 10.1:鏈路層概述
- 10.2:MAC地址的基本概念
- 10.3:初識ARP
- 10.4:以太網幀結構
- 10.5:IP地址映射為物理地址
- 10.6:ARP緩存表
- 10.7:ARP緩存表的超時處理
- 10.8:ARP報文
- 10.9:發送ARP請求包
- 10.10:數據包接收流程
- 10.10.1:以太網之數據包接收
- 10.10.2:ARP數據包處理
- 10.10.3:更新ARP緩存表
- 10.11:數據包發送流程
- 10.11.1:etharp_output()函數
- 10.11.2:etharp_output_to_arp_index()函數
- 10.11.3:etharp_query()函數
- 第11章:IP協議
- 11.1:IP地址.md
- 11.1.1:概述
- 11.1.2:IP地址編址
- 11.1.3:特殊IP地址