一、lwip的内存管理
lwip提供两种默认的内存分配策略,一个是内存堆(heap),一个是内存池(pool)。当然用户还可以对宏更改来改变内存分配定义,这里不细说。
1、内存池(pool)
内存池的效率高,不会产生内存碎片,但是只能分配固定大小的内存空间。LWIP需要知道内存需要哪种类型的pool,每种类型pool的大小,然后根据这个需求来分配内存空间。
以下是有关内存池的函数,这个一般是内核调用,用户不需要调用:
内存池初始化:memp_init( )
内存池分配:memp_malloc( )
内存池释放:memp_free( )
2、内存堆(heap)
内存堆的内存空间策略可以想象成是一个大数组,可以堆这个数组任意切割,随便申请任意大小的内存,但是频繁的申请和释放内存会导致过多的内存碎片,然后导致申请内存失败。这里还需要注意,内存堆对于内存申请时的大小有最小的内存规定(MINI_SIZE),LWIP默认是12个字节,但是这个值用户是可以自定义的。
以下是有关内存堆的函数,这个一般是内核调用,用户不需要调用:
内存堆初始化:mem_init( )
内存堆分配:mem_malloc( )
内存堆释放:mem_free( )
二、lwip数据包结构
lwip是就是TCP/IP协议栈,那么这些协议本质就是对数据包的处理,在lwip中使用了名为pbuf的结构体来管理数据包。
pbuf结构体如下:
struct pbuf
{
struct pbuf *next //构成链表时指向下一个pbuf数据包
void *payload //指向数据缓存区
u16_t tot_len //pbuf链表中所有pbuf的数据长度
/*这里的值是本包的len加前一包的tot_len,所以包尾的
tot_len=len*/
u16_t len //当前pbuf的数据长度
u8_t type //pbuf的类型
u8_t flags //状态
LWIP_PBUF_REF_T ref //用来记录当前pbuf被引用的次数
}
pbuf在内存分配时有以下类型,在pubuf.h文件中通过枚举pbuf_type来定义:
typedef enum {
PBUF_RAM //pbuf数据紧接着pbuf结构存储,pbuf数据存储在RAM中
PBUF_ROM //pbuf数据存储在ROM中
PBUF_REF //pbuf数据存储在RAM中,但是和pbuf结构的位置无关
PBUF_POOL //pbuf结构和其数据存储在同一内存池
} pbuf_type;
PBUF_RAM类型的pbuf空间是在lwip的内存堆中申请的,协议栈和应用程序中的待发送数据就是采用的这种方法,pbuf申请是在pbuf_alloc( )中进行的。最终申请的 PBUF_RAM类型的pbuf如下图所示:p指针首先指向数据,通过offset偏移来存储一些首部字段。
PBUF_POOL类型的pbuf空间是在lwip的内存池中申请的,并且lwip会申请两种类型的池:MEMO_PBUF(这个池子小)和MEMO_PBUF_POOL(这个池子大)。还有值得注意一点的是,比如下面申请了三个pbuf包来存储同一个数据包,只需要其中一个pbuf的offset偏移来存储有关pbuf数据包的信息即可,其他的pbuf不需要!
PBUF_REF和PBUF_ROM也是在lwip的内存池中申请的,但是只有一种类型的池MEMO_PBUF,并且只申请pbuf结构体,而不包含数据,他们的数据空间应用在其他地方的内存。
三、lwip网络接口管理
1、网络接口简介
网络接口层对应着我们实际的网卡,lwip支持多网口设计,lwip中使用netif来描述这些网口的特性,用链表netif_list来管理众多的网卡,当上层有数据需要发送时lwip就会从netif_list中挑选合适的网卡来发送。
2、