一LWIP學習筆記之資料報管理

2022-08-30 19:51:14 字數 4472 閱讀 6478

一、資料報管理   

tcp/ip 是一種資料通訊機制,因此,協議棧的實現本質上就是對資料報進行處理。 資料報管理應該能提供一種高效的機制,使協議棧各層能對資料報進行靈活的處理,同時減少資料在各層間傳遞時的時間與空間開銷,這是提高協議棧工作效率的關鍵點。 在 lwip 中,也有個類似的結構,稱之為 pbuf,本章所有討論將圍繞 pbuf 而展開。 

1、資料報結構pbuf

————pbuf.h————————————————————

struct

pbuf

;

tot_len 表示當前 pbuf 和其後所有 pbuf 的有效資料的總長度。pbuf 鍊錶中第乙個 pbuf 的 tot_len 字段表示整個資料報的長度,而最後乙個 pbuf 的 tot_len 欄位必同 len欄位相等 。

2、pbuf的型別

pbuf有4類:pbuf_ram、pbuf_rom、pbuf_ref、pbuf_pool系統中使用了乙個專門的列舉型別 pbuf_type 來描述它們: 

————pbuf.h——————————————————

typedef

enum

pbuf_type;

————————————————————————————————

pbuf_ram 型別的 pbuf 空間是通過記憶體堆分配得到的。這種型別的 pbuf 在協議棧中是使用得最多的,協議棧的待傳送資料和應用程式的待傳送資料一般都採用這個形式。申請 pbuf_ram型別 pbuf 時,協議棧會在記憶體堆中分配相應空間。 下面來看看源**是怎樣申請pbuf_ram 型的,在後續講解函式源**時也會詳細說到。 

p = (struct pbuf*)mem_malloc(lwip_mem_align_size(sizeof_struct_pbuf + offset) + lwip_mem_align_size(length));
分配成功的 pbuf_ram 型別 pbuf 如圖 7­1 所示。

從圖中可看出 pbuf 結構和相應資料在一片連續的記憶體區域中,注意 payload 並沒有指向整個資料區的起始處,而是間隔了一定區域。這段區域就是上面的 offset,它通常用來儲存資料報的各種首部字段,如 tcp 報文首部、ip 首部、乙太網幀首部等。 

pbuf_pool 型別和 pbuf_ram 型別的 pbuf 有很大的相似之處,但它的空間是通過記憶體池分配得到的。這種型別的 pbuf 可以在極短的時間內得到分配(得益於記憶體池的優點),在網絡卡接收資料報時,我們就使用了這種方式包裝資料。在申請 pbuf_pool 型別 pbuf 時,協議棧會在記憶體池 memp_pbuf_pool 中選擇乙個或多個pool,以滿足使用者空間大小的申請。源**是通過下面一條語句來完成 pool 申請的,其中 p 是pbuf 型指標。

p = memp_malloc(memp_pbuf_pool);
通常,使用者傳送的資料可能很長,所以系統會多次呼叫上面的語句,為使用者分配多個 pool,並把它們按照 pbuf 鍊錶的形式組織在一起,以保證使用者的空間請求要求。分配成功的 pbuf_pool 型別 pbuf 示意如圖 7­2所示。 

pbuf_rom 和 pbuf_ref 型別的 pbuf 基本相同,它們的申請都是在記憶體池中分配乙個相應的 pbuf結構(即 memp_pbuf 型別的 pool),而不申請資料區的空間 在傳送某些靜態資料時,可以採用這兩種型別的 pbuf,這將大大節省協議棧的記憶體空間。下面來看看源**是怎樣申請 pbuf_rom 和pbuf_ref 型別的,其中 p 是 pbuf 型指標。 

3、資料報申請函式

資料報申請函式有兩個重要的引數,一是想申請的資料報 pbuf 型別,這個剛說過了,不囉嗦;另乙個重要引數是該資料報是在協議棧中哪一層被申請的,分配函式會根據這個層次的不同,在 pbuf 資料區域前為相應的協議預留出首部空間,這就是前面所說的 offset 值了。總的來說,lwip 定義了四個層次,當資料報申請時,所處的層次不同,會導致預留空間的 offset值不同。層次的定義是通過乙個列舉型別 pbuf_layer 來實現的,如下**所示: 

————pbuf.h——————————————

#define pbuf_transport_hlen 20 //

tcp 報文首部長度

#define pbuf_ip_hlen 20 //

ip 資料報首部長度

typedef

enum

pbuf_layer;

pbuf_transport_hlen 和 pbuf_ip_hlen,前者是典型的 tcp 報文首部長度,而後者是典型的不帶任何選項欄位的 ip 首部長度

//

引數 layer,指定該 pbuf 資料所處的層次,分配函式根據該值在 pbuf 資料區預留出

//首部空間;length 表示需要申請的資料區長度,type 指出需要申請的 pbuf 型別

struct pbuf *pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)

p = pbuf_alloc(pbuf_raw, packetlength, pbuf_pool);
這個呼叫語句申請了乙個 pbuf_pool 型別的 pbuf,且其申請的協議層為 pbuf_raw,所以pbuf_alloc 函式不會在資料區前預留出任何首部空間;通過使用 p­>payload,就可以實現對 pbuf 中資料區的讀取或寫入操作了。

在 tcp 層要申請乙個資料報時,常常呼叫下面的語句:

p = pbuf_alloc(pbuf_transport, optlen, pbuf_ram)
它告訴資料報分配函式,使用 pbuf_ram 型別的 pbuf,且資料區前應該預留一部分的首部空間,由於這裡是 pbuf_transport 層,所以預留空間將有 54 位元組,即 tcp 首部長度pbuf_transport_hlen(20 位元組)、ip 資料報首部長度 pbuf_ip_hlen(20 位元組)以及乙太網幀首部長度(14 位元組)。當資料報往下層遞交,各層協議就可以直接操作這些預留空間中的資料,以實現資料報首部的填寫,這樣就避免了資料的拷貝。 

4、資料報釋放函式

假如現在我們的 pbuf 鍊錶由 a,b,c 三個 pbuf 結構連線起來,結構為 a­­­>b­­­>c,利用 pbuf_free(a)函式來刪除 pbuf 結構,下面用 abc 的幾組不同 ref值來看看刪除結果:

(1)1­>2­>3 函式執行後變為 ...1­>3,節點 bc 仍在;

(2)3­>3­>3 函式執行後變為 2­>3­>3,節點 abc 仍在;

(3)1­>1­>2 函式執行後變為......1,節點 c 仍在;

(4)2­>1­>1 函式執行後變為 1­>1­>1,節點 abc 仍在;

(5)1­>1­>1 函式執行後變為.......,節點全部被刪除。

假如在上面的第(4)種情況下,錯誤的呼叫資料報釋放函式,如 pbuf_free(b),這會導致嚴重的錯誤。

//

函式的返回值為成功刪除的 pbuf 個數

u8_t pbuf_free(struct pbuf *p)

當可以刪除某個 pbuf 結構時,函式 pbuf_free 首先檢查這個 pbuf 是屬於四個型別中的哪種,根 據類 型的不 同, 呼叫不 同的 記憶體釋 放函 數進 行刪 除。 

記憶體池memp_free->memp_pbuf_poll->pbuf_pool

->memp_pbuf->pbuf_rom  

->pbuf_ref

記憶體堆mem_free->pbuf_ram

5、其他資料報操作函式

pbuf_realloc 函式在相應 pbuf(鍊錶)尾部釋放一定的空間,將資料報 pbuf 中的資料長度減少為某個長度值。對於 pbuf_ram 型別的 pbuf,函式將呼叫記憶體堆管理中介紹到的 mem_realloc 函式,釋放這些多餘的空間;對於其他三種型別的 pbuf,該函式只是修改 pbuf 中的長度字段值,並不釋放對應的記憶體池空間。

pbuf_header 函式用於調整 pbuf 的 payload 指標(向前或向後移動一定的位元組數),在前面也說到過了,在 pbuf 的資料區前可能會預留一些協議首部空間,而 pbuf 被建立時,payload 指標是指向資料區的,為了實現對這些預留空間的操作,可以呼叫函式 pbuf_header 使 payload 指標指向資料區前的首部字段,這就為各層對資料報首部的操作提供了方便。當然,進行這個操作的時候,len和 tot_len 字段值也會隨之更新。

pbuf_take 函式用於向 pbuf 的資料區域拷貝資料;pbuf_copy 函式用於將乙個任何型別的 pbuf中的資料拷貝到乙個 pbuf_ram 型別的 pbuf 中。pbuf_chain 函式用於連線兩個 pbuf(鍊錶)為乙個 pbuf 鍊錶;pbuf_ref 函式用於將 pbuf 中的 ref 值加 1。 

LwIP協議棧學習之動態記憶體管理

lwip 的動態記憶體管理機制可以有三種 動態記憶體堆分配策略可以有兩種實現方式 通過開闢乙個記憶體堆,然後通過模擬 c 執行時庫的記憶體分配策略來實現。通過動態記憶體池的方式來實現,也即動態記憶體堆分配函式通過簡單呼叫動態記憶體池 pool 分配函式來完成其功能,此時,需要在標頭檔案lwippoo...

lwip學習筆記之幾個重要的資料結構詳解

struct pbuf pbuf資料結構用來儲存網路中傳輸的每乙個資料報。playload 指向資料報中的實際資料部分,即不包含各層資料報頭 len 該資料報中實際資料部分的長度 struct netbuf netbuf儲存的是本地某個 ip,port 與遠端某個 ip,port 連線之間的資料資訊...

Python學習筆記 資料包表之Excel操作模組

利用python操作excel的模組xlsxwriter,可以操作多個工作表的文字 數字 公式 圖表等。xlsxwriter模組具有以下功能 安裝xlsxwriter模組 1 python3 m easy install i xlsxwriter 例,實現插入文字 中英字元 數字 求和計算 單元格格...