LwIP之数据包管理
先看一下數(shù)據(jù)包結(jié)構(gòu)體pbuf
/* pbuf結(jié)構(gòu)體 */ struct pbuf {struct pbuf *next; //用于將pbuf連接成鏈表void *payload; //數(shù)據(jù)指針u16_t tot_len; //當(dāng)前以及后續(xù)所有pbuf包含的數(shù)據(jù)總長度u16_t len; //當(dāng)前pbuf的數(shù)據(jù)長度u8_t type; //pbuf類型u8_t flags; //狀態(tài)位u16_t ref; //pbuf被引用的次數(shù) };pbuf中有個成員type,表示pbuf的類型。pbuf共有四種類型PBUF_REF、PBUF_ROM、PBUF_POOL和PBUF_RAM。
/* pbuf類型 */ typedef enum {PBUF_RAM, /* pbuf和數(shù)據(jù)來自連續(xù)的內(nèi)存堆 */PBUF_ROM, /* pbuf來自內(nèi)存池MEMP_PBUF,數(shù)據(jù)來自ROM */PBUF_REF, /* pbuf來自內(nèi)存池MEMP_PBUF,數(shù)據(jù)來自RAM */PBUF_POOL /* pbuf和數(shù)據(jù)來自一個或多個內(nèi)存池MEMP_PBUF_POOL */ } pbuf_type;?
?
再看一下pbuf_layer,表示層類型,上層數(shù)據(jù)包需要為下層預(yù)留足夠空間用來填充頭部
/* pbuf分層類型 */ typedef enum {PBUF_TRANSPORT, //傳輸層PBUF_IP, //網(wǎng)絡(luò)層PBUF_LINK, //鏈路層PBUF_RAW //原始層 } pbuf_layer;?
下面看一下申請pbuf
/* 申請pbuf */ struct pbuf *pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) {struct pbuf *p, *q, *r;u16_t offset;s32_t rem_len;/* 根據(jù)pbuf所在層計算頭部偏移量 */offset = 0;switch (layer) {case PBUF_TRANSPORT:offset += PBUF_TRANSPORT_HLEN;case PBUF_IP:offset += PBUF_IP_HLEN;case PBUF_LINK:offset += PBUF_LINK_HLEN;break;case PBUF_RAW:break;default:return NULL;}/* 判斷pbuf類型 */switch (type) {/* PBUF_POOL類型 */case PBUF_POOL:/* 從內(nèi)存池MEMP_PBUF_POOL申請第一個單元 */p = memp_malloc(MEMP_PBUF_POOL);if (p == NULL) {return NULL;}/* 填充pbuf成員 */p->type = type;p->next = NULL;p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + (SIZEOF_STRUCT_PBUF + offset)));p->tot_len = length;p->len = LWIP_MIN(length, PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset));p->ref = 1;/* 判斷一個MEMP_PBUF_POOL單元夠不夠,如果不夠則繼續(xù)申請 */r = p;rem_len = length - p->len;while (rem_len > 0) {/* 從內(nèi)存池MEMP_PBUF_POOL申請單元 */q = memp_malloc(MEMP_PBUF_POOL);if (q == NULL) {pbuf_free(p);return NULL;}/* 填充pbuf成員 */q->type = type;q->flags = 0;q->next = NULL;/* 將pbuf連接起來 */r->next = q;/* 繼續(xù)填充pbuf成員 */q->tot_len = (u16_t)rem_len;q->len = LWIP_MIN((u16_t)rem_len, PBUF_POOL_BUFSIZE_ALIGNED);q->payload = (void *)((u8_t *)q + SIZEOF_STRUCT_PBUF);q->ref = 1;/* 更新剩余申請長度 */rem_len -= q->len;r = q;}break;/* PBUF_RAM類型 */case PBUF_RAM:/* 從內(nèi)存堆申請pbuf和數(shù)據(jù) */p = (struct pbuf *)mem_malloc(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length));if (p == NULL) {return NULL;}/* 填充pbuf成員 */p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset));p->len = p->tot_len = length;p->next = NULL;p->type = type;break;/* PBUF_ROM和PBUF_REF類型 */case PBUF_ROM:case PBUF_REF:/* 從內(nèi)存堆申請pbuf */p = memp_malloc(MEMP_PBUF);if (p == NULL) {return NULL;}/* 填充pbuf成員 */p->payload = NULL;p->len = p->tot_len = length;p->next = NULL;p->type = type;break;default:return NULL;}/* 引用次數(shù)為1 */p->ref = 1;/* 狀態(tài)為清空 */p->flags = 0;return p; }PBUF_RAM型
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
PBUF_POOL型
? ? ? ? ??
PBUF_ROM/PBUF_REF型
? ? ? ? ? ? ? ? ? ? ??
?
下面看一下pbuf釋放,當(dāng)沒有任何對象引用該pbuf的時候才能釋放,否則引用次數(shù)減一。
/* 釋放pbuf */ u8_t pbuf_free(struct pbuf *p) {u16_t type;struct pbuf *q;u8_t count;if (p == NULL) {return 0;}/* 循環(huán)釋放鏈表上的pbuf */count = 0;while (p != NULL) {u16_t ref;/* 引用次數(shù)減1 */ref = --(p->ref);/* 如果引用次數(shù)為0,則釋放 */if (ref == 0) {/* 釋放之前先找到下一個pbuf指針 */q = p->next;/* 根據(jù)pbuf類型,釋放pbuf內(nèi)存 */type = p->type;if (type == PBUF_POOL) {memp_free(MEMP_PBUF_POOL, p);} else if (type == PBUF_ROM || type == PBUF_REF) {memp_free(MEMP_PBUF, p);} else {mem_free(p);}/* 釋放個數(shù)加1 */count++;/* 更新下一個pbuf指針到當(dāng)前p */p = q;} /* 引用次數(shù)不為0,則停止釋放 */else {p = NULL;}}return count; }?
其它,lwip還提供了其它很多的API
收縮數(shù)據(jù)區(qū)函數(shù),從數(shù)據(jù)區(qū)尾部進(jìn)行釋放
/* 收縮pbuf數(shù)據(jù)區(qū) */ void pbuf_realloc(struct pbuf *p, u16_t new_len) {struct pbuf *q;u16_t rem_len;s32_t grow;/* 只能收縮不能擴展 */if (new_len >= p->tot_len) {return;}/* 數(shù)據(jù)擴展長度(負(fù)值) */grow = new_len - p->tot_len;/* 更新鏈表中每一個pbuf的tot_len變量,找出需要切割的第一個pbuf指針 */rem_len = new_len;q = p;while (rem_len > q->len) {rem_len -= q->len;q->tot_len += (u16_t)grow;q = q->next;}/* 當(dāng)前pbuf類型為PBUF_RAM,并且該pbuf需要切割 */if ((q->type == PBUF_RAM) && (rem_len != q->len)) {/* 當(dāng)前pbuf收縮內(nèi)存 */q = mem_realloc(q, (u8_t *)q->payload - (u8_t *)q + rem_len);}/* 調(diào)整當(dāng)前pbuf數(shù)據(jù)長度和后續(xù)數(shù)據(jù)長度 */q->len = rem_len;q->tot_len = q->len;/* 釋放后續(xù)pbuf */if (q->next != NULL) {pbuf_free(q->next);}q->next = NULL; }?
調(diào)整頭部pbuf有效數(shù)據(jù)指針
/* 調(diào)整pbuf有效數(shù)據(jù)指針 */ u8_t pbuf_header(struct pbuf *p, s16_t header_size_increment) {u16_t type;void *payload;u16_t increment_magnitude;if ((header_size_increment == 0) || (p == NULL))return 0;/* 調(diào)整長度 */if (header_size_increment < 0){increment_magnitude = -header_size_increment;} else {increment_magnitude = header_size_increment;}type = p->type;/* pbuf類型為PBUF_RAM和PBUF_POOL */payload = p->payload;if (type == PBUF_RAM || type == PBUF_POOL) {/* 調(diào)整pbuf有效數(shù)據(jù)指針 */p->payload = (u8_t *)p->payload - header_size_increment;/* 預(yù)留空間不夠調(diào)整 */if ((u8_t *)p->payload < (u8_t *)p + SIZEOF_STRUCT_PBUF) {p->payload = payload;return 1;}} /* pbuf類型為PBUF_REF和PBUF_ROM */else if (type == PBUF_REF || type == PBUF_ROM) {/* 向后調(diào)整 */if ((header_size_increment < 0) && (increment_magnitude <= p->len)) {p->payload = (u8_t *)p->payload - header_size_increment;}/* 不允許向前調(diào)整 */else {return 1;}}else {return 1;}/* 更新pbuf數(shù)據(jù)長度和pbuf鏈表數(shù)據(jù)總長度 */p->len += header_size_increment;p->tot_len += header_size_increment;return 0; }?
?
統(tǒng)計pbuf個數(shù)
/* 統(tǒng)計鏈表中有多少個pbuf */ u8_t pbuf_clen(struct pbuf *p) {u8_t len;len = 0;while (p != NULL) {++len;p = p->next;}return len; }?
引用次數(shù)加一
/* pbuf鏈表中第一個pbuf引用數(shù)加1 */ void pbuf_ref(struct pbuf *p) {if (p != NULL) {++(p->ref);} }
?
將兩個pbuf鏈表拼接起來,pbuf_cat和pbuf_chain。
pbuf_cat,t原來的調(diào)用者不需要使用pbuf_free。
pbuf_chain,t原來的調(diào)用者需要使用pbuf_free。
/* 將兩個pbuf鏈表拼接起來 */ void pbuf_cat(struct pbuf *h, struct pbuf *t) {struct pbuf *p;/* 調(diào)整第一個鏈表中pbuf的tot_len值 */for (p = h; p->next != NULL; p = p->next) {p->tot_len += t->tot_len;}p->tot_len += t->tot_len;/* 將兩個pbuf鏈表拼接起來 */p->next = t; } /* 將兩個pbuf鏈表拼接起來,并且后一個pbuf鏈表中第一個pbuf引用數(shù)加1 */ void pbuf_chain(struct pbuf *h, struct pbuf *t) {pbuf_cat(h, t);pbuf_ref(t); }?
解開pbuf
/* 將第一個pbuf和后面的鏈表解開 */ struct pbuf *pbuf_dechain(struct pbuf *p) {struct pbuf *q;u8_t tail_gone = 1;/* 第一個pbuf后面還有pbuf */q = p->next;if (q != NULL) {/* 調(diào)整后面pbuf數(shù)據(jù)的總長度 */q->tot_len = p->tot_len - p->len;/* 更新第一個pbuf參數(shù) */p->next = NULL;p->tot_len = p->len;/* 解開后釋放一次引用 */tail_gone = pbuf_free(q);if (tail_gone > 0) {}}/* 解開后pbuf鏈表首節(jié)點指針 */return ((tail_gone > 0) ? NULL : q); }?
數(shù)據(jù)拷貝
pbuf_copy,pbuf之間拷貝數(shù)據(jù)
pbuf_copy_partial,將pbuf數(shù)據(jù)拷貝出來
pbuf_take,將數(shù)據(jù)拷貝進(jìn)pbuf
/* pbuf之間拷貝 */ err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from) {u16_t offset_to=0, offset_from=0, len;/* 遍歷p_from鏈表 */do{/* 計算這次拷貝的數(shù)據(jù)長度 */if ((p_to->len - offset_to) >= (p_from->len - offset_from)) {len = p_from->len - offset_from;} else {len = p_to->len - offset_to;}/* 將數(shù)據(jù)拷貝過來 */MEMCPY((u8_t*)p_to->payload + offset_to, (u8_t*)p_from->payload + offset_from, len);/* 調(diào)整偏移量 */offset_to += len;offset_from += len;/* 目的pbuf數(shù)據(jù)區(qū)已滿,切換下一個pbuf */if (offset_to == p_to->len) {offset_to = 0;p_to = p_to->next;}/* 源pbuf數(shù)據(jù)區(qū)已空,切換下一個pbuf */if (offset_from >= p_from->len) {offset_from = 0;p_from = p_from->next;}/* 檢查錯誤 */if((p_from != NULL) && (p_from->len == p_from->tot_len)) {}if((p_to != NULL) && (p_to->len == p_to->tot_len)) {}} while (p_from);return ERR_OK; } /* 將pbuf中指定長度、指定位置的數(shù)據(jù)拷貝到指定內(nèi)存 */ u16_t pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset) {struct pbuf *p;u16_t left;u16_t buf_copy_len;u16_t copied_total = 0;left = 0;if((buf == NULL) || (dataptr == NULL)) {return 0;}/* 遍歷pbuf鏈表 */for(p = buf; len != 0 && p != NULL; p = p->next) {/* 數(shù)據(jù)不在當(dāng)前pbuf中 */if ((offset != 0) && (offset >= p->len)) {offset -= p->len;} /* 數(shù)據(jù)在當(dāng)前pbuf中 */else {/* 計算該pbuf中可以拷貝的數(shù)據(jù)長度 */buf_copy_len = p->len - offset;if (buf_copy_len > len)buf_copy_len = len;/* 將pbuf數(shù)據(jù)拷貝數(shù)據(jù)緩沖區(qū) */MEMCPY(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len);/* 計算已經(jīng)拷貝的數(shù)據(jù)長度 */copied_total += buf_copy_len;left += buf_copy_len;/* 計算剩余數(shù)據(jù)長度 */len -= buf_copy_len;/* 清空偏移量 */offset = 0;}}/* 拷貝的數(shù)據(jù)長度 */return copied_total; } /* 將數(shù)據(jù)拷貝到pbuf鏈表 */ err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len) {struct pbuf *p;u16_t buf_copy_len;u16_t total_copy_len = len;u16_t copied_total = 0;if ((buf == NULL) || (dataptr == NULL) || (buf->tot_len < len)) {return ERR_ARG;}/* 遍歷整個pbuf鏈表 */for(p = buf; total_copy_len != 0; p = p->next) {/* 計算該pbuf中可以拷貝的數(shù)據(jù)長度 */buf_copy_len = total_copy_len;if (buf_copy_len > p->len) {buf_copy_len = p->len;}/* 將數(shù)據(jù)拷貝pbuf數(shù)據(jù)緩沖區(qū) */MEMCPY(p->payload, &((char*)dataptr)[copied_total], buf_copy_len);/* 計算剩余數(shù)據(jù)長度和已經(jīng)拷貝數(shù)據(jù)長度 */total_copy_len -= buf_copy_len;copied_total += buf_copy_len;}return ERR_OK; }?
克隆pbuf
/* 在內(nèi)存堆中克隆一個指定層的pbuf鏈表,并釋放原有pbuf鏈表 */ struct pbuf *pbuf_coalesce(struct pbuf *p, pbuf_layer layer) {struct pbuf *q;err_t err;if (p->next == NULL) {return p;}/* 從內(nèi)存堆申請pbuf空間 */q = pbuf_alloc(layer, p->tot_len, PBUF_RAM);if (q == NULL) {return p;}/* 將數(shù)據(jù)從p拷貝到q */err = pbuf_copy(q, p);/* 釋放原pbuf鏈表 */pbuf_free(p);/* 返回新的pbuf鏈表指針 */return q; }?
總結(jié)
以上是生活随笔為你收集整理的LwIP之数据包管理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CANOpen状态机
- 下一篇: linux服务器程序开发,怎样搭建一个l