lwip【6】LWIP使用经验
LWIP使用经验
一 LWIP内存管理
LWIP的内存管理使用了2种方式:内存池memp和内存堆mem,如图1所示。
内存池的特点是预先开辟多组固定大小的内存块组织成链表,实现简单,分配和回收速度快,不会产生内存碎片,但是大小固定,并且需要预估算准确。
内存堆的本质是对一个事先定义好的内存块进行合理有效的组织和管理,主要用于任意大小的内存分配,实现较复杂,分配需要查找,回收需要合并,容易产生内存碎片,需要合理估算内存堆的总大小。
图1内存池与内存堆
1. 数据包管理
数据包管理结构pbuf共有四种类型,它们的特点和使用场合如表1所示。
|
类别 |
分配方式 |
特点 |
使用场合 |
|
PBUF_RAM |
内存堆,包括pbuf和数据区 |
长度不定,分配耗时 |
应用程序和协议栈 |
|
PBUF_POOL |
内存池,包括pbuf和数据区 |
长度固定,分配快 |
中断服务程序 |
|
PBUF_ROM |
内存池,仅包括pbuf |
所指数据位于ROM中 |
应用程序引用内存区 |
|
PBUF_REF |
内存池,仅包括pbuf |
所指数据位于RAM中 |
应用程序引用内存区 |
表1 pbuf类型与特点
每一种pbuf分配内存的方式都不一样,如图2所示。
图2四种数据包管理结构
只有选择合适的pbuf类型才能发挥LWIP的最大性能,一个数据包可能是多种pbuf的组合,用链表连接起来,如图3所示。
图3 pbuf链表
2. 设置内存大小
为LWIP开辟一个专用的内存堆是应该的,这样一来LWIP的mem_alloc()和mem_free()都将基于该堆内存进行分配和回收,不影响其他系统内存的使用。如图1左所示,lwipopt.h文件中宏MEM_SIZE定义了堆区的大小,对于一个负荷较重的系统堆区需要分配较大。
图4堆和PBUF_ROM内存区
LWIP使用PBUF_ROM类型的内存池来发送“只读”数据(处于ROM中或者其他进程中不可修改),宏MEMP_NUM_PBUF定义了该缓冲池的个数,如图2右所示。
在ISR(中断服务程序中)经常需要快速分配一部分内存进行数据存储,这是通过PBUF_POOL类型的缓冲区实现的。为此需要定义两个宏:PBUF_POOL_SIZE定义缓冲池的个数,PBUF_POOL_BUFSIZE定义单个缓冲区的大小,如图5所示。
图5 PBUF_POOL内存区
3 宏编译开关
若定义MEM_LIBC_MALLOC=1,直接使用C库中的malloc、free来分配动态内存;否则使用LWIP自带的mem_malloc、mem_free等函数。
若定义MEMP_MEM_MALLOC=1,则memp.c中的全部内容不会被编译,用内存堆来实现内存池分配,使用这种方式得考虑是否能忍受内存堆分配带来的时间延迟。
若定义MEM_USE_POOLS=1,则mem.c中的全部内容不会被编译,用内存池来实现内存堆的分配,使用这种方式得考虑是否能忍受因为POOL内存固定大小而带来的内存浪费。此外用户需要定义宏MEM_USE_CUSTOM_POOLS=1,还需要额外实现一个头文件lwippools.h,并在其中开辟一些用于内存堆分配函数的内存池POOL,开辟空间的格式如下:
LWIP_MALLOC_MEMPOOL_START
LWIP_MALLOC_MEMPOOL(20, 256)
LWIP_MALLOC_MEMPOOL(10, 512)
LWIP_MALLOC_MEMPOOL_END
二 LWIP启动时序
图6展示了LWIP启动时序,大部分函数都是LWIP自带的,主要的移植代码是eth_init()实现初始化以太网接口,启动程序会创建2个线程:tcpip_thread负责LWIP的绝大部分工作(主要是协议栈的解析和系统运行),ethernetif_thread负责从网口接收数据包再交付给tcpip_thread线程进行处理。
图6 LWIP启动函数
三 LWIP运行逻辑
1 接收数据包
图7接收数据包
当以太网口接收到一个数据包后,EMAC_IRQ中断服务程序通过信号量通知ethernetif线程,ethernetif线程调用low_level_input()接收该数据包并通过邮箱交付给tcpip_thread线程,tcpip_thread根据该数据包的类型进行相应处理。它是建立在消息传递的基础上的,如图8所示。
图8数据包消息的产生和处理
2 SequentialAPI函数调用
API设计的核心在于让用户进程负责尽可能多的工作,例如数据的计算、拷贝等;而协议栈进程只负责简单的通信工作,这是很合理的,因为系统可能存在多个应用程序,它们都使用协议栈进程提供的通信服务,保证内核进程的高效性和实时性是提高系统性能的重要保障。进程之间通信使用IPC技术,包括邮箱、信号量和共享内存,如图9所示。
图9协议栈API实现
以函数netconn_bind()为例看API是如何实现的,首先用户程序中调用函数netconn_bind()绑定一个连接,则这个函数实现时,是通过向内核进程发送一个TCPIP_MSG_API类型的消息,告诉内核进程执行do_bind函数:在消息发送后,函数阻塞在信号量上,等待内核处理该消息;内核在处理消息时,会根据消息内容调用do_bind,而do_bind会根据连接的类型调用内核函数udp_bind、tcp_bind或raw_bind;当do_bind执行完后,它会释放信号量,这使被阻塞的netconn_bind得以继续执行,整个过程如图10所示。
图10 API函数实现
四 TCP/IP核心知识点
1. 滑动窗口
图11滑动窗口
接收窗口相关的字段中,rcv_nxt是自己期望收到的下一个字节编号,rcv_wnd表示接收窗口的大小,rcv_ann_wnd表示将向对方通告的窗口大小值,这个值在报文发送时会被填在首部中的窗口大小字段,rcv_ann_right_edge记录了上一次窗口通告时窗口右边界取值。上面这四个字段都会随着数据的发送和接收动态地改变,如图12所示。
图12接收窗口
发送窗口中,lastack记录了被接收方确认的最高序列号,snd_nxt表示自己将要发送的下一个数据的起始编号,snd_wnd记录了当前的发送窗口大小,它常被设置为接收方通告的接收窗口值,snd_lbb记录了下一个被应用程序缓存的数据的起始编号,如图10所示。
上面这四个字段的值也是动态变化的,每当收到接收方的一个有效ACK后,lastack的值就做相应的增加,指向下一个待确认数据的编号,当发送一个报文后,snd_nxt的值就做相应的增加,指向下一个待发送数据,snd_nxt和lastack之间的差值不能超过snd_wnd的大小。
由于实际数据发送时是按照报文段的形式组织的,因此可能存在这样的情况:即使发送窗口允许,但并不是窗口内的所有数据都能发送以填满窗口,如图13中编号为11~13的数据,可能因为它们太小不能组织成一个有效的报文段,因此不会被发送。发送方会等到新的确认到来,从而使发送窗口向右滑动,使得更多的数据被包含在窗口中,这样再启动下一个报文段的发送。
图13发送窗口
2. 三次握手
图14连接建立过程
3. 断开连接
图15连接断开过程
4. TCP状态转换
图16 TCP状态转换图
5. 同时打开
图17双方同时打开
6. 同时关闭
图18双方同时关闭
五正确使用LWIP
一般说来LWIP协议栈是比较稳定的,尤其像V1.3.2经历过业界广泛使用和工程应用,完全可以应用于嵌入式产品。那为什么还是有很多人反映LWIP不稳定呢?主要是以下几个方面的原因:
1. 网络硬件驱动 确保EMAC口接收与发送稳定可靠
2. 移植LWIP 基于OS的移植代码正确稳定
3. 配置LWIP 根据设备RAM尺寸进行合理配置
1) 值(PBUF_POOL_SIZE * PBUF_POOL_BUFSIZE)必须大于TCP_SND_BUF和TCP_WND,否则容易引起错误;
2) 当内存有限时TCP发送不能太快(具体值依赖于分配内存的大小),否则引起tcp_enqueue()逻辑错误;
4. 调用LWIP的API函数 正确使用API函数,特别防止内存泄露。
5. 资源不足 打开报警提醒,当资源不够时提醒设计者
六 LWIP常见问题
1. 网卡驱动程序
首先,必须将协议栈完全初始化才能打开网络接收功能,接收中断必须将数据封装在PBUF中,然后交会给协议栈内核处理。其次,LWIP的全局变量(arp_table,netif_list,udp_pcbs等)确保赋初值0,否则容易一运行就崩溃。
2. 内存泄露
第一个原则(责任制):谁分配内存,谁就负责回收。
第二个原则(对称性):分配内存者与回收内存者一一对应构成闭环。
另外,需要特别注意一些系统函数的调用,它们也会带来内存泄露,如:
例1
newconn = netconn_accept(conn);
do_something_for(newconn);
netconn_close(newconn);
netconn_delete(newconn); /*一定要释放newconn否则将导致内存泄露 */
例2
inbuf = netconn_recv(conn);
do_something_for(inbuf);
netbuf_delete(inbuf); /*一定要释放inbuf否则将导致内存泄露 */
3. PC机无法与LWIP建立TCP连接
问题:PC机能够与LWIP设备PING操作成功,但是无法建立TCP连接。
原因:通过代码跟踪,发现LWIP发出了SYN+ACK数据包,但是PC机无法接收该握手数据包,该数据包为60字节,小于以太网的最小长度(64字节),而LWIP设备的EMAC没有设置短小数据包填充功能,导致PC机无法接收该短数据包。
解决:使能EMAC的短小数据包填充功能。
转自:http://blog.csdn.net/jiangjunjie_2005/article/details/26051399
lwip【6】LWIP使用经验的更多相关文章
- 【lwip】lwip源码基础
目录 前言 概念&作用 网络接口 概念引入 总结 lwip netif 结构体 链接 字段分析 网卡链表 网络 IP 接收数据函数 发送数据函数 ARP 模块调用的发送函数 出口回调函数 用户 ...
- LWIP使用经验---变态级(转)
源:LWIP使用经验---变态级 LWIP使用经验 一 LWIP内存管理 数据包管理 设置内存大小 宏编译开关 二 LWIP启动时序 三 LWIP运行逻辑 接收数据包 SequentialAPI函数调 ...
- LwIP移植和使用
LwIP移植和使用 本手册基于lwip-1.4.x编写,本人没有移植过1.4.0之前的版本,更早的版本或许有差别.如果看官发现问题欢迎联系<QQ: 937431539 email: 93743 ...
- LWIP互联网资料汇总
本文主要搜集了下互联网上关于LWIP的资料和教程 欢迎补充 第一部分:移植 LWIP在UCOS上移植 LWIP 在STM32上移植 http://www.docin.com/p-459242028 ...
- lwip移植到stm32上-enc28j60,103mcu(2)
前面小玩了一下ucos和lwip,但是都还不是真正的网络多任务,真正的网络多任务应该是什么样子的呢?应该是有一个专门的任务负责网络的通讯,他负责将数据发送出去,将数据接收回来,而其他的需要用到网络的任 ...
- 网络通信实验(2)TCP/IP LWIP 简介
TCP/IP 简介 TCP/IP 中文名为传输控制协议/因特网互联协议,又名网络通讯协议,是 Internet 最基本的协议. Internet 国际互联网络的基础,由网络层的 IP 协议和传输层的 ...
- LwIP Application Developers Manual3---链路层和网络层协议之IPV6,ICMP,IGMP
1.前言 本文主要讲述链路层和网络层的协议IPV6,ICMP 2.IPV6 2.1 IPV6特性 IPv6是IPv4的更新.其最显著的差别在于地址空间由32位转换成128位 2.2 从应用的角度看IP ...
- LwIP Application Developers Manual1---介绍
1.前言 本文主要是对LwIP Application Developers Manual的翻译 2.读者(应用开发手册的读者) 谁适合读这份手册 网络应用的开发者 想了解lwIP的网络应用开发者 阅 ...
- ETH—Lwip以太网通信
第39章 ETH—Lwip以太网通信 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/ ...
随机推荐
- PowerBuilder -- 数字金额大写
//==================================================================== // 事件: .pub_fc_change_number( ...
- 关于-O0、O1、O2、O3优化
少优化->多优化: O0 -->> O1 -->> O2 -->> O3 -O0表示没有优化,-O1为缺省值,-O3优化级别最高 整理自网络,仅供参考 1.- ...
- href=http:// href=// 的区别,src=http:// src=// 的区别。 链接里不带http,链接里直接使用双斜线 // 有什么不同。http://和//有什么区别?
其实很简单,当一个连接用双斜线 // 开头时表示如果浏览器当前使用的是https协议,那么就加载https协议的脚本,否则使用http,这保证了页面所有资源使用同一协议. 其实是有人将其做为规范来实践 ...
- [原]js获取dom元素的实际位置及相对坐标
关键API: Element.getBoundingClientRect() mdn:https://developer.mozilla.org/en-US/docs/Web/API/Element/ ...
- 云服务器 ECS Linux CentOS 修改内核引导顺序
由于 CentOS 7 使用 grub2 作为引导程序,所以和 CentOS 6 有所不同,并不是修改 /etc/grub.conf 来修改启动项,需要如下操作: 1. 查看系统内部有多少个内核: c ...
- transition_matrix Markov chain
- stacked generalization 堆积正则化 堆积泛化 加权特征线性堆积
https://en.wikipedia.org/wiki/Ensemble_learning Stacking Stacking (sometimes called stacked generali ...
- drawable animation基础
动画配置<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android: ...
- 使用pidof/kill组合命令,变相解决mediaserver内存泄漏【转】
本文转载自:https://blog.csdn.net/lj402159806/article/details/78950384 在5.1系统下mediaserver有内存泄漏的问题,原因在于使用ca ...
- 什么是XXX
1.什么事框架 框架式一组程序的集合,包含了一系列的最佳实践,作用是 解决某个领域的问题. 当我们使用某个框架时,其实是把一系列JAR包加载到CLASSPATH路径中,实际上是获得了JAR中所有对J ...