LWIP是TCP/IP协议栈的一种具体实现,本质就是对数据包的处理,在LWIP中使用一个被称为pbuf的结构管理数据包,
LWIP源码中的pbuf.c和pbuf.h这两个文件就是关于pbuf的,pbuf结构如下:
struct pbuf
{
struct pbuf *next; //构成链表的时候指向下一个pbuf
void *payload; //指向数据缓冲区
u16_t tot_len; //pbuf链表中所有pbuf的数据长度
u16_t len; //当前bpuf中的数据长度
u8_t type; //pbuf类型
u8_t flags; //状态
u16_t ref; //用来记录当前pbuf被引用的次数
};
数据类型
PBUF_RAM类型
case PBUF_RAM:
p = (struct pbuf*)mem_malloc(LWIP_MEM_ALIGN_SIZE\
(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length));
if (p == NULL) {
return NULL;
}
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_RAM类型的pbuf空间是从LWIP的内存堆中申请得到的,协议栈和应用程序中的待发送数据就是采用的这种方法。
pbuf的申请是在pbuf_alloc()中进行的,
PBUF_POOL类型
case PBUF_POOL:
p = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL);
if (p == NULL)
{
PBUF_POOL_IS_EMPTY();
return NULL;
}
p->type = type;
p->next = NULL;
p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + (SIZEOF_STRUCT_PBUF + offset)));
break;
PBUF_POOL类型的pbuf空间是从LWIP的内存池中申请得到的。
在LWIP初始化的时候就会自动的两类与pbuf相关的POOL:
MEMP_PBUF和MEMP_PBUF_POOL(在memp_std.h中)
MEMP_PBUF
- 用于PBUF_REF和PBUF_ROM这两类的
MEMP_PBUF_POOL
- 是用于PBUF_POOL类型的
PBUF_ROM和PBUF_REF类型
PBUF_ROM和PBUF_REF类型的pbuf空间也是从LWIP的内存池中申请得到的,分配方法都一样的,
他们使用内存池MEMP_PBUF,这两种类型申请的是指pbuf结构体的内存空间,并不包含数据空间,分配过程如下:
case PBUF_ROM:
case PBUF_REF:
p = (struct pbuf *)memp_malloc(MEMP_PBUF);
if (p == NULL)
{
return NULL;
}
p->payload = NULL;
p->len = p->tot_len = length;
p->next = NULL;
p->type = type;
break;
多种类型pbuf混合使用
数据包申请和释放
pbuf的申请和释放通过函数pbuf_alloc()和pbuf_free()来完成,
pbuf_alloc()函数和pbuf_free()函数原型如下:
pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
pbuf_free(struct pbuf *p)
pbuf_alloc()函数有两个重要的参数:
- layer
- layer决定是协议栈的哪一层申请的
- layer决定了pbuf中的offset,也就是pbuf数据区中卫协议预留的首部空间
- pbuf.h文件定义了一个枚举类型pbuf_layer来描述LWIP中的层,如下:
- type,,
- type决定申请的pbuf类型,
typedef enum {
PBUF_TRANSPORT,
PBUF_IP,
PBUF_LINK,
PBUF_RAW
} pbuf_layer;