LwIP协议栈(1):简介与pbuf

LwIP是一个轻量级的TCP/IP协议栈,设计用于资源有限的嵌入式系统。它包含IP、ICMP、UDP、TCP协议模块和操作系统模拟层,强调内存效率和API精简。LwIP通过动态内存池和pbuf结构管理数据包,pbuf采用链表结构适应不同大小的数据,并通过ref字段控制引用计数以管理内存。协议栈进程通常具有最高优先级,确保实时响应数据。
摘要由CSDN通过智能技术生成

概述
  Lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。
  LwIP是Light Weight (轻型)IP协议,有无操作系统的支持都可以运行。LwIP实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用,它只需十几KB的RAM和40K左右的ROM就可以运行,这使LwIP协议栈适合在低端的嵌入式系统中使用。[1]
  LwIP协议栈主要关注的是怎么样减少内存的使用和代码的大小,这样就可以让lwIP适用于资源有限的小型平台例如嵌入式系统。为了简化处理过程和内存要求,lwIP对API进行了裁减,可以不需要复制一些数据。
  LwIP 由几个模块组成,除 TCP/IP 协议的实现模块外( IP, ICMP, UDP, TCP),还有包括许多相关支持模块。这些支持模块包括:操作系统模拟层、缓冲与内存管理子系统、网络接口函数及一组 Internet 校验和计算函数。

进程模型
  LwIP 则采取将所有协议驻留在同一个进程的方式,以便独立于操作系统内核之外。应用程序既可以驻留在 LwIP 的进程中,也可以使用一个单独的进程。应用程序与 TCP/IP 协议栈通讯可以采用两种方法:一种是函数调用,这适用于应用程序与 LwIP 使用同一个进程的情况;另一种是使用更抽象的 API。
  LwIP 在用户空间而不是操作系统内核实现,既有优点也有缺点。把 LwIP 作为一个进程的主要优点是可以轻易的移植到不同的操作系统中。

操作系统模拟层
  为了方便 LwIP 移植,属于操作系统的函数调用及数据结构并没有在代码中直接使用,而是用操作系统模拟层来代替对这些函数的使用。操作系统模拟层使用统一的接口提供定时器、进程同步及消息传递机制等诸如此类的系统服务。原则上,移植 LwIP,只需针对目标操作系统修改模拟层实现即可。

缓冲与内存管理
  通讯系统里的内存与缓冲管理模块首要考虑的是如何适应不同大小的内存需求,一个TCP 段可能有几百个字节,而一个 ICMP 回显数据却仅有几个字节。还有,为了避免复制,应该尽可能的让缓冲区中的数据内容驻留在不能被网络子系统管理的存储区中,比如应用程序存储区或者 ROM。
  LWIP 的动态内存管理机制可以有三种:C运行时库自带的内存分配策略、动态内存堆(HEAP)分配策略和动态内存池(POOL)分配策略。默认情况下,我们选择使用 LWIP 自身的动态内存堆分配策略。

  一个典型的 LWIP 应用系统包括这样的三个进程:首先启动的是上层应用程序进程,然后是 LWIP 协议栈进程,最后是底层硬件数据包接收发送进程。通常 LWIP协议栈进程是在应用程序中调用 LWIP 协议栈初始化函数来创建的。注意 LWIP 协议栈进程一般具有最高的优先级,以便实时正确的对数据进行响应。

数据包pbuf:
  
  LwIP采用数据结构 pbuf 来描述数据包,其结构如下:
  
  

struct pbuf {
  /** next pbuf in singly linked pbuf chain */
  struct pbuf *next;

  /** pointer to the actual data in the buffer */
  void *payload;

  /**
   * total length of this buffer and all next buffers in chain
   * belonging to the same packet.
   *
   * For non-queue packet chains this is the invariant:
   * p->tot_len == p->len + (p->next? p->next->tot_len: 0)
   */
  u16_t tot_len;

  /** length of this buffer */
  u16_t len;

  /** pbuf_type as u8_t instead of enum to save space */
  u8_t /*pbuf_type*/ type;

  /** misc flags */
  u8_t flags;

  /**
   * the reference count always equals the number of pointers
   * that refer to this pbuf. This can be pointers from an application,
   * the stack itself, or pbuf->next pointers from a chain.
   */
  u16_t ref;
};

  各成员含义上面的注释已经说得很清楚了。
  关于采用链表结构,是因为实际发送或接收的数据包可能很大,而每个 pbuf 能够管理的数据可能很少,所以,往往需要多个 pbuf 结构才能完全描述一个数据包。
  另外,最后的 ref 字段表示该 pbuf 被引用的次数。这里又是一个纠结的地方啊。初始化一个 pbuf 的时候, ref 字段值被设置为 1,当有其他 pbuf 的 next 指针指向该 pbuf 时,该 pbuf 的 ref 字段值加一。所以,要删除一个 pbuf 时, ref 的值必须为 1 才能删除成功,否则删除失败。
  上图中注意 payload 并没有指向 ref 字段之后,而是隔了一定的区域。这段区域就是offset 的大小,这段区域用来存储数据的包头,如 TCP 包头, IP 包头等。当然, offset 也可以是 0。

来看代码:

/**
 * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type).
 *
 * The actual memory allocated for the pbuf is determined by the
 * layer at which the pbuf is allocated and the requested size
 * (from the size parameter).
 *
 * @param layer flag to define header size
 * @param length size of the pbuf's payload
 * @param type this parameter decides how and where the pbuf
 * should be allocated as follows:
 *
 * - PBUF_RAM: buffer memory for pbuf is allocated as one large
 *             chunk. This includes protocol heade
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

One2zeror

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值