收稿日期:2008唱08唱21;修回日期:2008唱10唱28 作者简介:王培东(1953唱),男,黑龙江哈尔滨人,教授,硕导,CCF会员,主要研究方向为计算机控制、计算机网络、嵌入式应用技术;吴显伟(1982唱),男(回族),河南南阳人,硕士,主要研究方向为计算机控制技术(wu_xianwei@126.com).一种自适应的嵌入式协议栈缓冲区管理机制王培东,吴显伟(哈尔滨理工大学计算机科学与技术学院,哈尔滨150080)摘 要:为避免创建缓冲区过程中必须指定大小和多次释放而导致可能的内存泄露和代码崩溃的弊端,提出一种自适应的嵌入式协议栈的缓冲区管理机制AutoBuf。
它是基于抽象缓冲区接口而设计的,具有自适应性,支持动态内存的自动分配与回收,同时实现了嵌入式TCP/IP协议栈各层之间的零拷贝通信。
在基于研究平台S3C44B0X的Webserver网络数据监控系统上的测试结果表明,该缓冲区的设计满足嵌入式系统网络通信的应用需求,是一种高效、可靠的缓冲区管理机制。
关键词:嵌入式协议栈;抽象缓冲区;零拷贝;内存分配中图分类号:TP316 文献标志码:A 文章编号:1001唱3695(2009)06唱2254唱03doi:10.3969/j.issn.1001唱3695.2009.06.077DesignandimplementationofadaptivebufferforembeddedprotocolstackWANGPei唱dong,WUXian唱wei(CollegeofComputerScience&Technology,HarbinUniversityofScience&Technology,Harbin150080,China)Abstract:Toavoidtraditionalmethodofcreatingbuffer,whichmusthavethesizeofbufferandfreememoryformanytimes,whichwillresultinmemoryleaksandcodescrash.ThispaperproposedaflexiblebuffermanagementmechanismAutoBufforembeddednetworkprotocolstack.Itwasadaptiveandscalableandbasedonanabstractbufferinterface,supporteddynamicme唱moryallocationandbackup.ByusingtheAutoBufbuffermanagementmechanismwithdatazerocopytechnology,itimplementedtotransferdatathroughtheembeddednetworkprotocolstack.ThemanagementmechanismhadbeenappliedtotheWebserversystembaseonS3C44b0Xplatformsuccessfully.Theresultsinrealnetworkconditionshowthatthesystemprovidesagoodper唱formanceandmeetsthenecessaryofembeddednetworksystem.Keywords:embeddedstack;abstractbuffer;zero唱copy;memoryallocation 随着网络技术的快速发展,主机间的通信速率已经提高到了千兆数量级,同时多媒体应用还要求网络协议支持实时业务。
嵌入式设备网络化已经深入到日常生活中,而将嵌入式设备接入到互联网需要网络协议栈的支持。
通过分析Linux系统中TCP/IP协议栈的实现过程,可以看出在协议栈中要有大量数据不断输入输出,而管理这些即时数据的关键是协议栈中的缓冲区管理机制,因此对嵌入式协议栈的缓冲区管理将直接影响到数据的传输速率和安全。
通用以太网的缓冲区管理机制,例如4.4BSDmbuf[1]和现行Linux系统中的sk_buf[2]多是在大内存、高处理速率的基础上设计的,非常庞大复杂。
由于嵌入式设备的硬件资源有限,特别是可用物理内存的限制,通用的协议栈必然不适用于嵌入式设备,在应用时要对标准的TCP/IP协议进行裁剪[3]和重新设计缓冲区管理机制。
1 缓冲区管理机制的性能需求分析缓冲区管理[4]是对内存提供一种统一的管理手段,通过该手段能够对可用内存提供分配、回收、数据操作等行为。
内存的分配操作是根据一定的内存分配策略从缓冲区中获得相应大小的内存空间;缓冲区的数据操作主要是向缓冲区写数据,从缓冲区读数据,在缓冲区中删除数据,对空闲的内存块进行合并等行为;内存的回收就是将已空闲的内存重新变为可用内存,以供存储其他新的数据。
为了满足长度不一的即时数据的需求,缓冲区对内存的操作主要集中在不断地分配、回收、合并空闲的内存块等操作。
因为网络中的数据包小到几个字节大到几千个字节,不同长度的数据对内存的需求必然不同。
现存嵌入式设备中的内存多是以物理内存,即实模式形式存在的,没有虚拟内存的形式,对内存的操作实际是操作真实的物理内存,所以对内存操作要特别谨慎。
在传统使用动态分配的缓冲区(通过调用malloc()/free())在函数之间传递数据。
尽管该方法提供了灵活性,但它也带来了一些性能影响。
首先考虑对缓冲区的管理(分配和释放内存块)。
如果分配和释放不能在相同的代码位置进行,那么必须确保在某个内存块不再需要时,释放一次(且仅释放一次)该内存块是很重要的,否则就会导致内存泄露。
其次是必须确定缓冲区的大小才能分配该内存块。
然而,确定数据大小并非那么容易,传统做法是采用最大的数据尺寸的保守估计。
而采用保守估计预分配的内存大小总是远超过实际需要的大小,而且没有一定的范围标准,这样难免会导致资源的严重浪费。
随着数据在协议栈中的不断流动,内存块的多次释放和多次分配是难以避免的,而保守估计对于有限的资源来说又是一种浪费的策略。
因此为了能有效地利用资源,设计一种可自控的、不用预判断大小的数据缓冲区接口就势在必行。
第26卷第6期2009年6月 计算机应用研究ApplicationResearchofComputersVol.26No.6Jun.2009由于嵌入式设备资源的限制,嵌入式缓冲区管理机制的设计性能[5]要达到以下几点要求:a)高效性。
嵌入式设备的实时性要求缓冲区的分配与回收必须快,尽量减少延迟,能满足实时数据的存储与释放。
b)可靠性。
一方面是系统的内存请求必须得到满足;另一方面必须避免内存分配中的内存泄露问题,一旦内存泄露,则可能带来系统崩溃的危险。
c)持久性。
嵌入式设备一般要运行很长时间,系统尽可能减少资源的浪费,降低碎片的产生,提高内存的利用率,保证系统的稳定。
自适应缓冲区的设计要有以下能力:a)在有限的内存空间可以存放不同长度的数据。
b)尽量减少因存储和释放不同长度数据产生的内存碎片。
c)尽量减少分配和回收时遍历的次数。
d)尽量减少对预分配的内存进行长度估计。
e)尽量减少缓冲区之间的数据拷贝操作。
另外,为了更好地利用嵌入式设备的资源,需要优化通用协议栈,使得缓冲区的分配和回收简单、高效,提高内存的利用率。
2 缓冲区管理机制AutoBuf的分析与设计缓冲区的分配一般有以下两种策略[5]:a)静态分配。
是指内存在程序编译时已经确定好了大小,内存范围是固定不变的,实现简单,只要在系统设计时设定一个足够大的缓冲区可以接收最大的数据包就行了。
这种实现方法数据结构简单、操作方便,但是可能造成内存的浪费,产生资源竞争问题并且不便于动态操作。
b)动态分配。
是指根据系统运行时的需要,根据某种内存分配策略动态地满足用户申请的需求。
实现机制相对于静态机制来说比较灵活,为系统的实现带来极大的方便,可以随着数据包的到来不断地扩充内存块链表,避免了固定缓冲区分配中即使小数据包也要占据大内存空间的浪费现象,提高了内存的利用率;而且不存在固定共享资源的竞争,从而在同一时间可以处理多个数据包,增强数据的处理能力。
但由于数据包的长度不一,在分配内存时可能会产生碎片问题。
综观静态分配和动态分配,动态分配相对于静态分配在资源利用方面是比较有优势的。
本文采用动态分配策略来设计协议栈的缓冲区,同时提出一种抽象的缓冲区接口设计来最大程度地减少内存碎片发生的概率,使缓冲区的管理更加灵活,更好地利用内存资源。
2畅1 抽象缓冲区接口的设计根据应用对象Webserver对网络的需求,参考4.4BSDMbuf和Linux中的sk_buf[6]的设计,本文提出一种抽象的动态缓冲区管理机制,该机制具有自适应性的管理内存,支持动态的内存分配、回收。
一般数据缓冲区的分配是由两个操作完成的,即数据缓冲区实体的定义和实际内存的分配[7]。
然而事实上,在实际数据变得可用之前,其实是不需要分配实际的内存。
根据这样的思想可以将两个操作分离开来。
为了表示抽象的数据缓冲区接口,需要新定义两个数据结构:typedefstructBufferBlockHeader_stBufferBlockHeader{BufferBlockHeader倡pNextBlock;longint currentLength;shortint used;shortint flag;unsignedchar倡startPoint;unsignedchar倡endPoint;};//对要分配的内存块实体的定义typedefstructBuffer_stBuffer{longinttotalLength;BufferBlockHeader倡pFirstBlock;BufferBlockHeader倡pLastBlock;};//已创建的抽象缓冲区接口的信息。
AutoBuf包含关于已创建的抽象缓冲区的信息,它还管理动态存储的内存块的一个链表。
如果分配了内存,BufferBlockHeader结构中的pNextBlock总是指向该链表中的下一个内存块。
每个内存块在分配时都包含一个BufferBlockHeader头,后面跟着一个用于存储实际数据的缓冲区块。
CurrentLength是表示当前数据包的长度,一般当前数据的长度是小于一个MTU的;flag是标志当前的内存块是否被引用,flag=0则认为是未被引用;used是表示该内存块是否空闲,used=0则表示其是空闲块则可以被回收;startPoint和endPoint是两个界限指针主要是界定数据包的范围;totalLength记录当前存储在缓冲区链表中所有未发或已经接收的数据包的总大小;pFirstBlock指向该链表中的第一个内存块,pLastBlock指向该链表的最后一个内存块,这两个指针界定总分配的内存范围,避免在释放时的内存泄露。