APP下载

LwIP协议栈的pbuf结构探索与研究

2018-03-01

单片机与嵌入式系统应用 2018年2期
关键词:数据包内存嵌入式

(西安工程大学 电子信息学院,西安 710048)

引 言

随着工业 4.0 的提出和工业以太网的普及,越来越多的工业设备急需接入 Internet[14-15]。 以太网是嵌入式系统的一个重要模块[8]。实现嵌入式设备的互联必须要有网络协议的支持[4]。LwIP在嵌入式通信中占有很重要的地位,主要是由于其占用资源较少。实验表明,运行该协议只需要20 KB的RAM和40 KB的ROM[2]。LwIP协议为数据通信提供了基础[5]。pbuf结构对于LwIP而言是非常重要的,它关系到数据存放的问题,由于不同类型pbuf的内存分配方式有所不同,那就意味着将会储存不同类型的数据包。如果对pbuf没有一个深刻的了解和认识,就不能灵活地运用pbuf的类型。灵活运用pbuf的类型对于数据包的接收和发送是非常重要的[13],如果不能合理地分配储存空间的大小和pbuf类型,可能导致数据丢失和空间的浪费。为了解决上述问题,本文对pbuf结构进行了深度分析,并设计了内存分配实验。

1 pbuf结构介绍

LwIP是瑞士计算机科学院开发的一套用于嵌入式系统的开源TCP/IP协议栈[7,12],用于嵌入式系统的开放源代码的 TCP/IP 协议栈[8]。 LwIP提供一系列函数实现IP、TCP、UDP等操作[10]。对数据包如何进行处理,在LwIP“轻型IP协议(Light Weight IP)”[21]中是非常重要的一个环节。在网卡驱动编写时最核心的部分是数据的存储与传输方式[6]。而在LwIP中主要利用4种不同类型的pbuf来对数据包进行分类管理。

由于实际存入pbuf结构的数据可能会很大,所以需要由多个pbuf才可以实现对数据包的存放。这些pbuf可以是相同的类型,也可以是多种类型的混合使用。pbuf的申请和释放是通过两个函数pbuf_alloc()和pbuf_free()来完成的,pbuf_alloc()函数中含有两个重要的参数:layer和type,其中枚举类型pbuf_layer通过参数layer决定是协议栈的哪一层(PBUF_TRANSPORT、PBUF_IP、PBUF_LINK以及PBUF_RAW)和pbuf中的offset“偏移量”。pbuf的类型主要通过枚举类型Pbuf_type体现出来,然后根据参数type的不同进行不同的选择,最后再通过switch语句选择用哪一种类型。LwIP中的 pbuf 有4种类型: PBUF_POOL、PBUF_RAM、PBUF_ROM、PBUF_REF[1]。pbuf结构如下:

struct pbuf {

struct pbuf *next; /*指向下一个pbuf*/

void *payload; /*指向数据缓冲区*/

u16_t tot_len; /*所有pbuf的数据长度*/

u16_t len; /*当前pbuf的数据长度*/

u8_t type; /*pbuf类型*/

u8_t flags /*状态标志*/

u16_t ref; /*记录当前pbuf被引用次数*/

};

2 pbuf类型的探索与研究

2.1 PBUF_RAM类型

PBUF_RAM类型的pbuf是从LwIP的内存堆中申请得到的,主要用来储存协议栈和应用程序中的待发送数据,所以在学习和了解PBUF_RAM之前要先对内存堆的结构进行分析和了解。从图 1内存堆的结构示意图中可以看出,每一个被分配的存储块都包含一个小的结构。其结构体的成员变量分别包括next、prev以及used。为了能够更加清楚地了解内存堆的分配状况,特意对其组织结构图进行了颜色区别,其中阴影部分表示被分配(used 被置位为1),否则为0。内存堆组织结构还可以通过*next和*prev将相邻的结构块连接起来。在内存堆分配内存时需要注意:在其分配时每个内存块的大小是有一定差异的,而且可能会随时变动。在对内存堆分析过后,再对PBUF_RAM类型的pbuf进行代码讲解,其源代码主要在源文件pbuf.c中。其部分代码如下:

case PBUF_RAM:

p=(structpbuf*)mem_malloc(LwIP_MEM_ALIGN_S

IZE(SIZEOF_STRUCT_PBU+offset)+LwIP_MEM_ALIGN_SIZE(length));

/*获取PBUF_RAM类型内存大小*/

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;

图2 PBUF_RAM类型的pbuf结构

通过源代码可知,PBUF_RAM类型的pbuf结构内存的大小分别包括offset、length和SIZEOF_STRUCT_PBU。其中offset表示一个偏移量里面用来存储一些首部字段,如TCP报文首部、IP首部等。由于next和payload占用4个字,然而tot_len、len和ref占用2个字节,type和flags为1个字节,因为图2中每一行分配为4个字节,所以next和payload各占用一行,tot_len和len两者共同占用一行,而type、flags和ref三者共同占用一行,最后的空白区域表示数据存储区。又因为其先后顺序不同,最终申请的PBUF_RAM类型的pbuf结构如图2所示。

2.2 PBUF_POOL类型

PBUF_POOL类型的pbuf与PBUF_RAM类似,都包括offset、length和SIZEOF_STRUCT_PBU,不同之处在于两者申请内存的地方不同,从而导致特性不同,由于分配PBUF_POOL速度快,所以可以用来存放对分配内存速度要求较高的数据。其部分代码如下:

p=(structpbuf*)memp_malloc(MEMP_PBUF_POOL);

/*获取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其内存是从MEMP_PBUF_POOL中申请得到的,所以能够通过在MEMP_PBUF_POOL中改变宏定义PBUF_POOL_SIZE的大小来设置内存池的个数,通过改变PBUF_POOL_BUFSIZE的数值来改变内存池大小。但是其不能设置的太大,要根据数据实际应用的大小来定义,因为每个POOL都具有固定大小,如果设置太大会造成内存的浪费[16],如果设置太小可能会出现以下问题:

① 每个pbuf结构在内存池中占用的内存大小是一定的,假如POOL设置太小,就会导致内存利用率下降;

② 如果pbuf中数据区分配太小,可能会导致数据分组首部信息得存放到下一个pbuf结构中,从而导致操作不方便。

事实上,应用程序发送和接收的数据可能会远远大于一个PBUF_POOL所存储的数据量,而且内存池类型的内存分配每次分配到的大小是固定的,图3所示一般需要多个PBUF_POOL类型并通过指针next指向下一个PBUF_POOL类型,从而使多个PBUF_POOL类型链接成一个链表,用于存储数据分组。虽然经过多次分配构成一个链表,但是它们仍然是一个数据包,因此只有第一个pbuf有offset来存储有关数据包的信息,其余的则不需要。

图3 PBUF_POOL

2.3 PBUF_ROM和PBUF_REF类型

图4 PBUF_ROM和PBUF_REF

PBUF_ROM、PBUF_REF与PBUF_POOL一样都是从内存池中申请得到的,但是不同之处是它们使用的是内存池MEMP_PBUF。如图4所示,这两种类型的pbuf所申请的内存主要是用来存放pbuf结构体,并没有给数据空间申请内存,但是这两个的数据空间可以应用其它地方的内存(RAM/ROM)进行数据存储。

3 pbuf的释放

在对pbuf进行内存释放的时候是通过调用pbuf_free()来完成,当释放pbuf的时候,LwIP会自动检测pbuf的类型,然后再调用相关的函数进行相对应的删除。但是在对其内存进行释放的时候需要先满足一定的条件,其中主要是通过检测ref“引用(reference)”的大小,只有当ref的数值不小于1的时候,pbuf才有可能被释放,但不是一定会被释放,当有其它类型的pbuf通过next指针指向该pbuf的时候,其相对应的ref的值就会相对应的增加1,当释放pbuf的时候其先对应的那个ref数值也会相对应的减去1。当有多个pbuf结构连接在一起时,释放第一个pbuf时,该pbuf链的第二个节点就会成为pbuf链的第一个节点同时会自动检测pbuf节点是否被其它的所引用,即判断ref是否大于1,如果不大于则继续删除,否则终止。

4 试验结果

本实验是在以Cortex-M3为内核的开发板上进行[9],对PBUF_RAM类型的pbuf在RAM中的内存分配和释放进行模拟实验,探究了其如何进行内存分配和存储数据以及如何进行内存的释放。因为pbuf的类型较多,而且在对数据管理的时候可能为多种类型混合使用,不易针对某个类型的pbuf进行单独内存分配和释放实验。对该内存堆的操作类似于C语言中的malloc/free[1,3]。所以该实验主要是通过运用malloc/free函数在内部内存RAM分配和释放内存的方式来模拟PBUF_RAM在RAM中的分配和释放[16-18],并通过LCD进行字符串的存储地址、写入的字符串,以及RAM使用率的显示。

其中图5、图6中的SRAMIN USED字样表示RAM的使用率,Addr用来表示数据存放的地址。通过图5可以看出,当向内部内存RAM中写入字符串“Memory Malloc Test123”时,其内存使用率为10%,存储地址为0X2000 92C0,说明已经将字符串写入到RAM中。图6是对其内存释放,可以看出其内存使用率减小,其地址变为0X0000 0000,表明将RAM中的数据进行了释放,但是其内存使用率理论上应该为0,这里的5%就是内存碎片。由于嵌入式系统的内存空间是非常宝贵的,尤其对于数据的传输而言,如果每次传输都产生碎片,那就是资源的浪费。所以对pbuf结构的分析与探究是非常必要的。

图5 内存申请

图6 内存释放

结 语

[1] 付晓军,夏应清,何轩.嵌入式LwIP协议栈的内存管理[J].电子技术应用,2006(3):56-57.

[2] 来爱华,卢军,游继安.基于LwIP协议的多点控制系统研究[J].湖北工程学院学报,2016,36(3):28-33.

[3] 蔡雄飞,王新华,郭淑琴.嵌入式TCP/IP协议LwIP的内存管理机制研究[J].杭州电子科技大学报,2012,32(4):118-121.

[4] 王祖云,杨思国,王建伟,等.嵌入式LwIP协议栈的移植与测试研究[J].计算机与数字工程,2014,42(2):272-275,318.

[5] 赵智增,冯春鹏.基于STM32的以太网接口转多串口透传模块设计[J]. 山西电子技术,2016(2):30-33.

[6] 曹绍华,史永宏.基于32位处理器的网络驱动及协议栈研究[J].现代电子技术,2016,39(19):317-321.

[7] 张齐,劳炽元.轻量级协议栈LwIP的分析与改进[J].计算机工程与设计,2010,31(10):2169-2171,2256.

[8] 韩德强,杨淇善,王宗侠,等.基于μC/OS-III的LwIP协议栈的移植与实现[J].电子技术应用,2013,39(5):18-21.

[9] 杨明极,祝庆峰,李硕.基于STM32的嵌入式网络控制器设计[J].测控技术,2014,33(10):93-96.

[10] 徐立艳.基于ARM和LabVIEW的网络数据采集测试系统设计[J].现代电子技术,2016,39(5):24-27,32.

[11] 高罗卿,庄源昌.基于LwIP协议的嵌入式远程监控终端的研发与实现[J].电气自动化,2015,37(1):49-51.

[12] 刘培刚,杜靖中.基于μC/OS-II和LwIP嵌入式设备以太网通信研究与实现[J].电子设计工程,2017,25(16):129-133.

[13] 薛建彬,郭燕波,许洋,等.LwIP在微控制系统中的移植与应用[J].数字技术与应用,2016(10):2.

[14] 周一兵,刘宪鹏.LwIP 在嵌入式系统中的应用[J].科技视界,2013(6):40.

[15] 曹辉.基于μC/OS-III的嵌入式web服务器的应用研究[J].自动化技术与应用,2016,35(2):36-39.

[16] 鄢涛,于曦.基于C++的高效内存池的设计与实现[J].成都大学学报:自然科学版,2017,36(3):257-261.

[17] Bryant R E.深入理解计算机系统[M].龚奕利,等译.北京:北京机械工业出版社,2016.

[18] Wang N,Liu X,He J,et al.Collaborative memory pool inCluster system[C]//International Conference on ParallelProcessing,007.China:Xi'an,2007.

[19] 侯捷.STL 源码剖析[M].武汉:华中科技大学出版社,2002.

[20] HAN D,YANG Q,WANG Z,et al.Implementationof LwIP porting based on μC/OS-III[J].Application of Electronic Technique,2013.

[21] 蒋俊,钟伟胜.μC/OS-II和LwIP的并发服务器与代理线程设计模式[J].单片机与嵌入式系统应用,2014(12):42-44.

徐健(副教授),主要研究方向为电能质量、数字信号处理;孙庆,主要研究方向为计算机控制网络。

猜你喜欢

数据包内存嵌入式
外部高速缓存与非易失内存结合的混合内存体系结构特性评测
“春夏秋冬”的内存
SmartSniff
搭建基于Qt的嵌入式开发平台
嵌入式软PLC在电镀生产流程控制系统中的应用
Altera加入嵌入式视觉联盟
倍福 CX8091嵌入式控制器
基于内存的地理信息访问技术
视觉注意的数据包优先级排序策略研究
移动IPV6在改进数据包发送路径模型下性能分析