C 如何最好地处理分层协议堆栈中的大型缓冲区?

C 如何最好地处理分层协议堆栈中的大型缓冲区?,c,api,embedded,buffer,C,Api,Embedded,Buffer,我正在为一个小型嵌入式系统(多点,rs485类型的东西)开发一个简单的协议栈。在此堆栈中,losely在OSI层之后建模: 应用 网络 数据链 物理(串行驱动程序) 每一层都有自己的页眉/页脚部分,用于包装其上方层的有效负载 我将使用自己的静态分配的固定大小块缓冲池来存储二进制数据包。(此应用程序中没有malloc/免费。) 在其他API中,我看到数据通常作为具有相关长度的常量指针传递。以这种方式,数据将需要在每一层进行复制操作,因为上面层的有效负载被放置在当前层的新分配的缓冲区中 对于三层堆栈

我正在为一个小型嵌入式系统(多点,rs485类型的东西)开发一个简单的协议栈。在此堆栈中,losely在OSI层之后建模:

  • 应用
  • 网络
  • 数据链
  • 物理(串行驱动程序)
  • 每一层都有自己的页眉/页脚部分,用于包装其上方层的有效负载

    我将使用自己的静态分配的固定大小块缓冲池来存储二进制数据包。(此应用程序中没有malloc/免费。)

    在其他API中,我看到数据通常作为具有相关长度的常量指针传递。以这种方式,数据将需要在每一层进行复制操作,因为上面层的有效负载被放置在当前层的新分配的缓冲区中

    对于三层堆栈,这将是2个复制操作和3个分配的缓冲区

    有没有更好的方法来做到这一点,并且仍然保持协议层的干净分离

    为了更好地锚定讨论,让我们假设数据包通常在2k左右,处理器是一个小型8位微处理器,运行频率为8Mhz

    在其他API中,我看到数据通常作为具有相关长度的常量指针传递。以这种方式,数据将需要在每一层进行复制操作,因为上面层的有效负载被放置在当前层的新分配的缓冲区中

    我猜您正在给出一个传输缓冲区的API示例


    我想你可以保持同样的API,如果您添加了一个限制,即调用此API的人在收到传输操作已完成的后续通知之前,不允许再次使用或触摸该缓冲区:这样调用API就隐式地转移了该缓冲区的所有权。

    您可以通过让每个层请求为空来避免复制来自下一个较低层的缓冲区,而不是分配一个:

    • 应用层请求缓冲区 网络层的长度为LA
    • 网络层从数据链路层请求缓冲区长度LA+LN
    • 数据链路层从物理层请求缓冲区长度LA+LN+LD
    • 物理层从缓冲池中提取缓冲区
    • 物理层将
      buffer+phdr\u len
      返回到数据链路层
    • 数据链路层向网络层返回
      buffer+phdr\u len+dhdr\u len
    • 网络层将
      buffer+phdr\u len+dhdr\u len+nhdr\u len
      返回到应用层
    • 应用层在提供的缓冲区中填写数据,并调用网络层进行传输
    • 网络层在报头前面加上前缀并调用数据链路层进行传输
    • 数据链路层在报头前面加上前缀,并调用物理层进行传输
    • 物理层在头文件前面加上前缀并传递给硬件

    创建缓冲区结构。了解底层的最大大小后,在顶层分配足够的缓冲区空间,以便在每个后续层进入堆栈时对其进行预处理。当添加一个层时,每个层在缓冲区结构中移动指针

    在底层,缓冲区的开始记录在缓冲区结构的指针中。要发送的数据位于连续缓冲区中。没有在每个层复制任何数据


    从下到上剥离缓冲区结构中的层。

    或者,不同层的头不需要是连续的(在单个缓冲区中):相反,它们可以使用“分散-聚集”API位于不同的缓冲区中。谢谢@caf,我也在考虑这一可能的解决方案。在get_buffer()调用时,上层将负责缓冲区。在每一层上,除了发送(pbuf)之外,还需要一个空闲的_buffer(),以防出现问题,这样才能正确地释放缓冲区。这是最简单的方法,因为它只需要一个缓冲区,而不需要复制。对于从设备,缓冲区通常在物理层中定义,因为这是消息产生的地方。如果您有不同的数据包类型,您只需要引用另一种类型的结构指针。问题是顶层需要知道每个下层需要多少,这是OP试图避免的紧密耦合(我相信这就是“协议层的干净分离”的含义)@caf:的确如此。对于从设备,通常是底层保存缓冲区。这很方便地避免了这个问题,因为最大消息大小通常是底层规范的一部分。如果顶层确实必须保存缓冲区,那么顶层就必须知道此信息。我想这是两个中较小的一个邪恶,如果资源有限!此方法的成功通常取决于您对协议栈和设备驱动程序的控制程度。我曾在一些低功耗嵌入式系统上工作过,在这些系统中,我可以完全控制协议栈和驱动程序-避免线程/层之间的复制可以提高吞吐量。8b它是8Mhz和2kB的微型数据包?你没有提到可用的ram,但我猜数据包几乎填满了它,而你显然在运行一个“单一进程”。我想我看不出为什么要为这样一个简单的系统创建这么多层和抽象。将其分为“数据传输”和“应用程序”并通过指向全局的指针传递有效负载。@Mark,协议栈将在不同的平台上使用,其中一个是带有8k ram的Atmega1281。它的时钟频率可以为20Mhz,但出于电源原因,我们不这样做。我可以放松关注点的分离,但这不是我问题的重点。@Mark,关于2k缓冲区,我认为你是对的kely不能做得那么大,但对于这个应用来说,越大越好,因为它是高延迟数据通道(卫星),我不打算添加窗口(就像TCP那样)。