协议栈的内存管理单元采用了buddy伙伴算法 。上述三个宏的关系参见BUDDY_MEM_SIZE宏的注释 。前面说过,mmu管理的内存用于协议栈的不同业务情形,其中最核心的一种业务情形就是socket,用户分配的内存大小直接决定了用户编写网络应用时能够申请的socket数量 。如果你在申请分配一个新的socket时报ERRREQMEMTOOLARGE(The requested memory is too large, please refer to the macro definition BUDDY_MEM_SIZE)或ERRNOFREEMEM(The mmu has no memory available)错误,则意味着内存已经不够用了,需要你增加内存或者检视你的代码看是否存在未及时释放的socket句柄 。另外,决定内存利用效率的关键配置项是BUDDY_PAGE_SIZE宏,因为mmu分配内存的最小单位就是“页” 。这个宏设置单个内存页的大小 , 单位为字节 , 其值必须是2的整数次幂 。如果你的通讯报文不大,建议把页面大小调整的小一些,比如16字节、32字节等,以尽量减少单个页面的空余字节数 。
sys_config.h文件的其余宏均为协议层相关的配置项 。这其中有几个与底层网络接口相关的配置项需要特别关注:
#define SUPPORT_PPP 1 //* 是否支持ppp模块:1,支持;0 , 不支持,如果选择支持,则系统会将ppp模块代码加入到协议栈中#if SUPPORT_PPP#define APN_DEFAULT"4gnet"//* 根据实际情况在这里设置缺省APN#define AUTH_USER_DEFAULT"card"//* ppp认证缺省用户名#define AUTH_PASSWORD_DEFAULT "any_char" //* ppp认证缺省口令#define PPP_NETLINK_NUM1 //* 协议栈加载几路ppp链路(系统存在几个modem这里就指定几就行)#define SUPPORT_ECHO1 //* 对端是否支持echo链路探测#define WAIT_ACK_TIMEOUT_NUM 5 //* 在这里指定连续几次接收不到对端的应答报文就进入协议栈故障处理流程(STACKFAULT),这意味着当前链路已经因严重故障终止了#else#define PPP_NETLINK_NUM 0#endif#define SUPPORT_ETHERNET 1 //* 是否支持ethernet:1,支持;0,不支持#if SUPPORT_ETHERNET#define ETHERNET_NUM 1//* 要添加几个ethernet网卡(实际存在几个就添加几个)#define ARPENTRY_NUM 32 //* arp条目缓存表的大小,只要不小于局域网内目标通讯节点的个数即可确保arp寻址次数为1,否则就会出现频繁寻址的可能 , 当然这也不会妨碍正常通讯逻辑,只不过这会降低通讯效率#else#define ETHERNET_NUM 0#endif
如果目标系统需要用到ppp拨号,我们在打开协议栈对ppp模块的支持后还需要设置缺省的拨号参数值,比如apn、拨号账号及密码等 。当然你也可以不用设置,后面我们在编写os适配层接口的时候也会设置这几项 。系统会使用os适配层的设置值代替缺省值 。另外协议栈在设计之初即考虑支持多路ppp同时拨号的情形,目标系统支持几路ppp , 宏PPP_NETLINK_NUM值置几即可 。SUPPORT_ECHO宏指定ppp链路是否启用echo回显探测功能 。某些ppp接入服务商可能会关闭此项功能 , 如果你不确定,建议缺省情况下关闭此功能 。因为echo链路探测功能一旦被启用,协议栈会每隔一小段时间发送探测报文到对端 。对端如果不支持此功能会丢弃该探测报文不做任何响应,这将导致协议栈判定ppp链路故障,从而主动结束链路、重新拨号 。
协议栈同样支持多路ethernet网卡,ETHERNET_NUM宏用于指定目标系统存在几路ethernet网卡 。这里需要特别注意的是ARPENTRY_NUM宏,这个宏用于指定ethernet网络环境下进行通讯时mac地址缓存表的大小 。如果缓存表过小,进行通讯的目标地址并不在缓存表中时,协议栈会先发送arp查询报文 , 得到对端的mac地址后才会发送实际的通讯报文 。虽然这一切都是协议栈自动进行的 , 但通讯效率会受到影响 。如果目标系统的内存够用,建议放大缓存表的容量,最合理的大小是等于计划通讯的目标地址的数量 。
其余协议层相关的配置项均属于ip及其支持的上层协议:
//* ip支持的上层协议相关配置项//* ===============================================================================================#define SUPPORT_IPV6 0 //* 是否支持IPv6:1,支持;0,不支持#define SUPPORT_SACK 0//* 系统是否支持sack项,sack项需要协议栈建立发送队列,这个非常消耗内存,通用版本不支持该项#define ICMPRCVBUF_SIZE_DEFAULT 128//* icmp发送echo请求报文时指定的接收缓冲区的缺省大?。?注意 , 如果要发送较大的ping包就必须指定较大的接收缓冲区#define TCPRCVBUF_SIZE_DEFAULT2048//* tcp层缺省的接收缓冲区大小,大小应是2^n次幂才能最大限度不浪费budyy模块分配的内存#define TCPUDP_PORT_START20000 //* TCP/UDP协议动态分配的起始端口号#define TCP_WINDOW_SCALE0//* 窗口扩大因子缺省值#define TCP_CONN_TIMEOUT30//* 缺省TCP连接超时时间#define TCP_ACK_TIMEOUT3//* 缺省TCP应答超时时间#define TCP_MSL15//* 指定TCP链路TIMEWAIT态的最大关闭时长:2 * TCP_MSL,单位:秒#define TCP_LINK_NUM_MAX16//* 系统支持最多建立多少路TCP链路(涵盖所有TCP客户端 + TCP服务器的并发连接数),超过这个数量将无法建立新的tcp链路#if SUPPORT_ETHERNET#define TCPSRV_BACKLOG_NUM_MAX 10 //* tcp服务器支持的最大请求队列数量,任意时刻所有已开启的tcp服务器的请求连接队列数量之和应小于该值,否则将会出现拒绝连接的情况#define TCPSRV_NUM_MAX2//* 系统能够同时建立的tcp服务器数量#define TCPSRV_RECV_QUEUE_NUM64 //* tcp服务器接收队列大?。?所有已开启的tcp服务器共享该队列资源,如果单位时间内到达所有已开启tcp服务器的报文数量较大,应将该值调大#endif#define UDP_LINK_NUM_MAX 4//* 调用connect()函数连接对端udp服务器的最大数量(一旦调用connect()函数,收到的非服务器报文将被直接丢弃)#define SOCKET_NUM_MAX16 //* 系统支持的最大SOCKET数量,如实际应用中超过这个数量则会导致用户层业务逻辑无法全部正常运行(icmp/tcp/udp业务均受此影响) , 其值应大于等于TCP_LINK_NUM_MAX值#define IP_TTL_DEFAULT64 //* 缺省TTL值#define ROUTE_ITEM_NUM8//* 系统路由表数量//* ===============================================================================================
推荐阅读
- 开源网络协议栈onps诞生记
- <一>从指令角度了解函数堆栈调用过程
- stm32h750移植lvgl
- 3 Python全栈工程师之从网页搭建入门到Flask全栈项目实战 - 入门Flask微框架
- 都卷Java,你看看你得学多少技术栈才能工作!
- flutter系列之:flutter中可以建索引的栈布局IndexedStack
- SpringBoot+Vue3 AgileBoot - 手把手一步一步带你Run起全栈项目
- C++ 使用栈求解中缀、后缀表达式的值
- 1 Python全栈工程师之从网页搭建入门到Flask全栈项目实战 - ES6标准入门和Flex布局
- windows C++ 异常调用栈简析