lwipopts.H设置

首先要知道有4中类型的数据,在pbuf.H里面有:

typedef enum {
  PBUF_RAM, /* pbuf data is stored in RAM */
  PBUF_ROM, /* pbuf data is stored in ROM */
  PBUF_REF, /* pbuf comes from the pbuf pool */
  PBUF_POOL /* pbuf payload refers to RAM */
} pbuf_type;
既然都是pbuf,那么分配内存都用这个函数pbuf_alloc,函数原型为:

struct pbuf *
pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)

最后一个参数为类型。

看一下这个函数内部,如下:

  /* pbuf references existing (non-volatile static constant) ROM payload? */
  case PBUF_ROM:
  /* pbuf references existing (externally allocated) RAM payload? */
  case PBUF_REF:
    /* only allocate memory for the pbuf structure */
    p = memp_malloc(MEMP_PBUF);
    if (p == NULL) {
      LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
                  ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n",
                  (type == PBUF_ROM) ? "ROM" : "REF"));
      return NULL;
    }
    /* caller must set this field properly, afterwards */
    p->payload = NULL;
    p->len = p->tot_len = length;
    p->next = NULL;
    p->type = type;
    break;
  default:
发现PBUF_ROM后面竟然没有break,就说明 PBUF_ROM和 PBUF_REF在pbuf_alloc函数内部是一样处理方式。

先说PBUF_ROM和PBUF_REF这两种,这两个对应在lwipOPTS.H里面的宏定义为:

/* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application
   sends a lot of data out of ROM (or other static memory), this
   should be set high. */
#define MEMP_NUM_PBUF           100

我把这个宏定义MEMP_NUM_PBUF设置为0,竟然程序也好用。于是我在函数pbuf_alloc的case PBUF_REF里面加个断点,竟然整个程序运行过程中,没有进入到这个断点。这就解释我为啥将这个宏定义设置为0也好用了。


老衲五木的这篇文章要看看,非常好。《LwIP协议栈源码详解——TCP/IP协议的实现》数据包pbuf当然还有这篇《LwIP协议栈源码详解——TCP/IP协议的实现》动态内存管理),这篇文章提到的“LWIP中常用到的内存分配策略有两种,一种是内存堆分配,一种是内存池分配”,

说内存堆分配有碎片产生,我的理解是只要申请内存和释放内存一 一对应起来就不会产生碎片。

其实这几篇文章我记得几年前看过,并且研究的比较透彻,现在竟然又都忘了不少,幸好能想起一些。内存堆不用链表 串联起来。而内存池MEMP_PBUF_POOL需要用链表串联起来。内存池MEMP_PBUF这个有点特殊,就是上文关于REF和ROM的,就是这个宏定义#define MEMP_NUM_PBUF           100

这个东东却是稍微耗费点内存,每个耗费16字节(每个耗费这么少!!那么不管实际程序用不用得到,完全可以把这个值设置大一点)。(注:耗费的这16个字节我估计是因为结构体形式的变大导致的,并没有把指向的实际内存变大。)MAP显示是bss区域,就是数组的形式耗费。

memp.C中有一部分变量通过const关键字放到了ROM里面,如下:

    .constdata                               0x080101e2   Section       36  memp.o(.constdata)
    memp_sizes                               0x080101e2   Data          18  memp.o(.constdata)
    memp_num                                 0x080101f4   Data          18  memp.o(.constdata)

还有一部分以数组形式耗费了RAM,如下:

    .bss                                     0x20007ba8   Section    12699  memp.o(.bss)
    memp_tab                                 0x20007ba8   Data          36  memp.o(.bss)
    memp_memory                              0x20007bcc   Data       12663  memp.o(.bss)

耗费最猛的就是这个老哥了,如下:

/** This is the actual memory used by the pools (all pools in one big block). */
static u8_t memp_memory[MEM_ALIGNMENT - 1 
#define LWIP_MEMPOOL(name,num,size,desc) + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) )
#include "lwip/memp_std.h"
];

那么memp_std.h"里面有各种POOL,而lwipopts.H和opt.H里面的宏定义很多都来自memp_std.h。

在memp_STD.H里面摘几个常用的:

#if LWIP_UDP
LWIP_MEMPOOL(UDP_PCB,        MEMP_NUM_UDP_PCB,         sizeof(struct udp_pcb),        "UDP_PCB")
#endif /* LWIP_UDP */


#if LWIP_TCP
LWIP_MEMPOOL(TCP_PCB,        MEMP_NUM_TCP_PCB,         sizeof(struct tcp_pcb),        "TCP_PCB")
LWIP_MEMPOOL(TCP_PCB_LISTEN, MEMP_NUM_TCP_PCB_LISTEN,  sizeof(struct tcp_pcb_listen), "TCP_PCB_LISTEN")
LWIP_MEMPOOL(TCP_SEG,        MEMP_NUM_TCP_SEG,         sizeof(struct tcp_seg),        "TCP_SEG")
#endif /* LWIP_TCP */


#if (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) /* LWIP_TIMERS */
LWIP_MEMPOOL(SYS_TIMEOUT,    MEMP_NUM_SYS_TIMEOUT,     sizeof(struct sys_timeo),      "SYS_TIMEOUT")
#endif /* LWIP_TIMERS */

LWIP_PBUF_MEMPOOL(PBUF,      MEMP_NUM_PBUF,            0,                             "PBUF_REF/ROM")
LWIP_PBUF_MEMPOOL(PBUF_POOL, PBUF_POOL_SIZE,           PBUF_POOL_BUFSIZE,             "PBUF_POOL")

可见在lwipopts.H里面的如下设置都是在memp_std.h里面的:

/* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application
   sends a lot of data out of ROM (or other static memory), this
   should be set high. */
#define MEMP_NUM_PBUF           0
/* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One
   per active UDP "connection". */
#define MEMP_NUM_UDP_PCB        6
/* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP
   connections. */
#define MEMP_NUM_TCP_PCB        5
/* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP
   connections. */
#define MEMP_NUM_TCP_PCB_LISTEN 60
/* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP
   segments. */
#define MEMP_NUM_TCP_SEG        16
/* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active
   timeouts. */
#define MEMP_NUM_SYS_TIMEOUT    10




/* ---------- Pbuf options ---------- */
/* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */
#define PBUF_POOL_SIZE          6


/* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */
#define PBUF_POOL_BUFSIZE       1500



=======================

下一步分析mem.C就是上文提到的内存堆。

看下mem.C占内存情况:

    .data                                    0x2000006c   Section       12  mem.o(.data)
    ram                                      0x2000006c   Data           4  mem.o(.data)
    ram_end                                  0x20000070   Data           4  mem.o(.data)
    lfree                                    0x20000074   Data           4  mem.o(.data)


    .bss                                     0x20000394   Section    30740  mem.o(.bss)

占用30740字节的数组名字是ram_heap

    ram_heap                                 0x20000394   Data       30740  mem.o(.bss)

在mem.C里面找到这个变量定义:

/** If you want to relocate the heap to external memory, simply define
 * LWIP_RAM_HEAP_POINTER as a void-pointer to that location.
 * If so, make sure the memory at that location is big enough (see below on
 * how that space is calculated). */
#ifndef LWIP_RAM_HEAP_POINTER
/** the heap. we need one struct mem at the end and some room for alignment */
u8_t ram_heap[MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT];
#define LWIP_RAM_HEAP_POINTER ram_heap
#endif /* LWIP_RAM_HEAP_POINTER */

这个宏MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT当中,MEM_SIZE_ALIGNED 是最大的,看一下MEM_SIZE_ALIGNED 是啥?

#define MEM_SIZE_ALIGNED     LWIP_MEM_ALIGN_SIZE(MEM_SIZE)

看到了吧就是MEM_SIZE,我在lwipopts.H里面有宏定义如下:

/* MEM_SIZE: the size of the heap memory. If the application will send
a lot of data that needs to be copied, this should be set high. */
#define MEM_SIZE                (30*1024)

而30*1024=30720 可见其他部分占据30740-30720=20字节。

那么MEM_SIZE这个值设置为多少好呢?这个就得看实际应用了。可以每次分配完后,监视一下剩余多少。不知道有没有这个功能?如果没有的话,估计是因为碎片化的原因,碎片多了,统计剩余内存就没有意义了。可以统计下最后用到的内存块之后的区域有多少啊。这样心里有数。也可以在分配内存的时候关注下分配了多少,然后把程序中所有的都加起来。

最后关注一下在lwipopts.H里面的这个MEMP_NUM_SYS_TIMEOUT这个宏定义,

在opt.H里面有

/**
 * MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts.
 * (requires NO_SYS==0)
 * The default number of timeouts is calculated here for all enabled modules.
 * The formula expects settings to be either '0' or '1'.
 */
#ifndef MEMP_NUM_SYS_TIMEOUT
#define MEMP_NUM_SYS_TIMEOUT            (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT)
#endif

上面这个关系到函数LwIP_Periodic_Handle里面用到的定时功能。

还有在memp_std.h里面有

#if (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) /* LWIP_TIMERS */
LWIP_MEMPOOL(SYS_TIMEOUT,    MEMP_NUM_SYS_TIMEOUT,     sizeof(struct sys_timeo),      "SYS_TIMEOUT")
#endif /* LWIP_TIMERS */

然后再lwipopts.H里面有

/**
 * NO_SYS==1: Provides VERY minimal functionality. Otherwise,
 * use lwIP facilities.
 */
#define NO_SYS                  1


/**
 * NO_SYS_NO_TIMERS==1: Drop support for sys_timeout when NO_SYS==1
 * Mainly for compatibility to old versions.
 */
#define NO_SYS_NO_TIMERS        1

然后我把MEMP_NUM_SYS_TIMEOUT设置为2,竟然程序可以正常跑。

看了一下timer.H里面的

/* Timers are not supported when NO_SYS==1 and NO_SYS_NO_TIMERS==1 */
#define LWIP_TIMERS (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS))

相当于#define LWIP_TIMERS 0

就是timer功能没用上,那么函数LwIP_Periodic_Handle里面的timer是啥?在lwipopts.H里面有个注释写到:

/**
 * NO_SYS_NO_TIMERS==1: Drop support for sys_timeout when NO_SYS==1
 * Mainly for compatibility to old versions.
 */

所以说是不是涉及到新老版本。

所以这里就糊里糊涂吧。不关心这个问题。

就把lwipopts.H里面如下定义

#define MEMP_NUM_SYS_TIMEOUT    10





好的分析到这里,这篇文档大半已过,还有一部分内容就是 关于TCP的设置了。


就是下面这些东东:

/* ---------- TCP options ---------- */
#define LWIP_TCP                1
#define TCP_TTL                 255


/* Controls if TCP should queue segments that arrive out of
   order. Define to 0 if your device is low on memory. */
#define TCP_QUEUE_OOSEQ         0


/* TCP Maximum segment size. */
#define TCP_MSS                 (1500 - 40)   /* TCP_MSS = (Ethernet MTU - IP header size - TCP header size) */


/* TCP sender buffer space (bytes). */
#define TCP_SND_BUF             (8*TCP_MSS)


/*  TCP_SND_QUEUELEN: TCP sender buffer space (pbufs). This must be at least
  as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. */


#define TCP_SND_QUEUELEN        (2* TCP_SND_BUF/TCP_MSS)


/* TCP receive window. */
#define TCP_WND                 (2*TCP_MSS)


一个一个分析,先看TCP_QUEUE_OOSEQ         ,如下

/* Controls if TCP should queue segments that arrive out of
   order. Define to 0 if your device is low on memory. */
#define TCP_QUEUE_OOSEQ         0

好了,知道设置为0就可以了。至于是啥作用,不关心。

然后再看TCP_MSS ,看到其他几个宏定义都是TCP_MSS 的倍数。

看下opt.H里面咋讲的?如下:

/**
 * TCP_MSS: TCP Maximum segment size. (default is 536, a conservative default,
 * you might want to increase this.)
 * For the receive side, this MSS is advertised to the remote side
 * when opening a connection. For the transmit size, this MSS sets
 * an upper limit on the MSS advertised by the remote host.
 */
#ifndef TCP_MSS
#define TCP_MSS                         536
#endif

看了下注释,基本上是看不懂,先去百度一下再回来。

弄接个链接,一个是华为的:TCP中的MSS解读,内容如下:

MSS 是TCP选项中最经常出现,也是最早出现的选项。MSS选项占4byte。MSS是每一个TCP报文段中数据字段的最大长度,注意:只是数据部分的字段,不包括TCP的头部。TCP在三次握手中,每一方都会通告其期望收到的MSS(MSS只出现在SYN数据包中)如果一方不接受另一方的MSS值则定位默认值536byte。
MSS值太小或太大都是不合适。太小,例如MSS值只有1byte,那么为了传输这1byte数据,至少要消耗20字节IP头部+20字节TCP头部=40byte,这还不包括其二层头部所需要的开销,显然这种数据传输效率是很低的。MSS过大,导致数据包可以封装很大,那么在IP传输中分片的可能性就会增大,接受方在处理分片包所消耗的资源和处理时间都会增大,如果分片在传输中还发生了重传,那么其网络开销也会增大。因此合理的MSS是至关重要的。MSS的合理值应为保证数据包不分片的最大值。对于以太网MSS可以达到1460byte.
不MSS相似的在IP层也有一个类似的概念---MTU(Maximum Transfer Unit)下图可以清晰翻译MSS不MTU 的关系:

1

MTU=uMSS+TCP Header+IP Header.

还有http://blog.csdn.net/xiaofei0859/article/details/51052848里面说:

 TCP在三次握手建立连接过程中,会在SYN报文中使用MSS(Maximum Segment Size)选项功能,协商交互双方能够接收的最大段长MSS值。
       MSS是传输层TCP协议范畴内的概念,顾名思义,其标识TCP能够承载的最大的应用数据段长度,因此,MSS=MTU-20字节TCP报头-20字节IP报头,那么在以太网环境下,MSS值一般就是1500-20-20=1460字节。
客户端与服务器端分别根据自己发包接口的MTU值计算出相应MSS值,并通过SYN报文告知对方。

所以本博主可以看出wireshark上标记SYN的帧,就有MSS相关内容。

好弄个实际例子试一试,

在服务器程序上把#define TCP_MSS                 (1400 - 40)

于是握手帧如下:

6

看到了吧,客户端请求用1460字节传输数据,但是服务器答应只能用1360字节传输。

然后传个文件试一试,如下:

5

看到了吧,果真是用1360字节交互。

从客户端向服务器传送文件看一下:

f

看到了吧,也是用1360传输的。同时看到我的服务器接收能力太差,导致显示TCP WINDOWS FULL。(我分析是因为我的服务器接收能力差导致的,因为写入文件系统太耗费时间了)。这个以后再议。

所以到这里TCP_MSS就可以说基本搞清楚了。可见TCP_MSS是对某一方来说,接收和发送都用的上的,是服务器和客户端双方协商的结果。

------------

下面是关于TCP_SND_BUF,下面这个链接有点介绍,看起来比较详细:

https://www.cnblogs.com/byeyear/p/3525433.html,如下:

// TCP发送缓冲区大小(已发出但还未收到ACK的最大允许数据量)
// 只是设定大小,并不实际分配内存
// 如果你的程序需要发送大量零拷贝数据
// 可以将这个值设大一些
// (因为零拷贝数据“总是在那里”,不占LwIP动态内存)
// 最小不应小于单次调用tcp_write时可能发送的最大数据量
// 调用tcp_write时的参数len若大于tpcb->snd_buf将导致返回ERR_MEM
// (在LwIP代码中,每成功执行一次tcp_write相应减小tpcb->snd_buf,
// 每收到一次ACK相应增加tpcb->snd_buf)
// 考虑到一般系统“隔一个确认”的原则,
// 一般设置为TCP_MSS的2倍或更大的值。
#ifndef TCP_SND_BUF
#define TCP_SND_BUF (2 * TCP_MSS)
#endif
找遍所有的C函数,在函数tcp_new里发现了一处用的哦啊TCp_SND_BUF的地方,如下:

pcb->snd_buf = TCP_SND_BUF;

那么看看那些地方用到了pcb->snd_buf,如下:

bbb

事实上我还漏了一个重要的地方,在tcp.H里面,如下

#define          tcp_sndbuf(pcb)          ((pcb)->snd_buf)

哈哈,这个地方也不太重要了。

那么这个地方pcb->snd_buf有时候++有时候--的,到底是咋个回事呢?

我先百度一下,等会再回来,等会开午饭了。




  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值