栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

lwip笔记

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

lwip笔记

1. 动态内存管理
  • 动态内存管理的概念及常见策略

    • 分配的时间效率问题

    • 高效回收已释放的内存空间

    • 避免内存碎片,将相邻的小空闲块合并成大空闲块

    • 常见分配策略

      1. 规定申请内存时,申请大小必须指定为某几个固定值(如4,8,16等),否则不予分配。被称为动态内存池分配,用简单的链表将空闲块连接起来,效率高,但会产生内存浪费的现象。

      2. 初始化几个固定大小的内存链表(4,8,16),如果用户请求5,但是8号链表分配完了,就从16号链表截取8个字节,将剩余的8个字节插入8号链表中。可能会导致大内存块被多次划分成独立的小内存块。这个时候需要对上述链表进行重新组织,即内存紧缩操作。

      3. 各个空闲块的大小合数量随着系统运行而改变,申请n个字节。但是系统中的多个空闲块长度都大于n:

        • 首次拟合,将找到的第一个长度不小于n的空闲块分配给用户,将其剩余空间重新组织为一格小的空闲块插入链表中。目前使用最多的策略,称为内存堆分配。

        • 最佳拟合,找到长度和n最接近的空闲块,系统中的空闲块会被按照空间由小到大的顺序组织起来,内存回收比较慢。

        • 最差拟合,从系统中最大的空闲块划分出n个字节,空闲链表通常也是按照空间由大到小的顺序进行组织的,分配无需查找,释放需要遍历链表

        • 分析

          a. 最佳拟合适用于用户请求大小范围较广的系统,系统中会产生很小甚至无法再被使用的内存片

          b. 最差拟合,会使得空闲链表中的空闲块大小趋于均匀,适用于内存请求大小范围较窄的系统

          c. 首次拟合是随机的,介于上述两者之间,适用于不知道运行期间用户请求大小的情况。

          d. 首次拟合,分配需要遍历链表,释放插入表头;

          最差拟合,从表头分配,释放需要遍历链表;

          最佳拟合,分配和释放都需要遍历链表。

      4. 内存回收时,尽量将地址相邻的空闲块合并成更大的空闲块。

  • 动态内存池管理

    ##:连接符,连接两个Token为一个Token(Token是编译原理中的概念,可以是关键字,也可以是变量)

    #:将其后的宏参数字符串化

    #define ERROR_IF(expression) {if(expression) printf("error:"#expression "n");}
    
    ERROR_IF(a==b)
    {if(a==b) printf("error:""a==b""n");}
    
    名称类型描述
    memp_t枚举为每类POOL定义一个名称/编号
    memp_tab[]全局型指针数组指向每类POOL中的第一个POOL
    memp_sizes[]全局型数组每类POOL中的单个POOL的大小
    memp_num[]全局型数组每类POOL中的POOL的个数
    memp_desc[]全局型指针数组指向每类POOL的描述字符串
    memp_memory[]全局型数组为所有POOL分配的内存空间
    typedef enum{
        #define LWIP_MEMPOOL(name,num,size,desc) MEMP_##name,
        #include "lwip/memp_std.h"
        MEMP_MAX
    }memp_t;
    
    struct memp{
        struct memp *next;
    };
    
    void memp_init(void);
    void *memp_malloc(memp_t type);
    void memp_free(memp_t type,void *mem);
    

  • 动态内存堆管理

    名称类型描述
    ram_heap[]全局型数组系统堆内存空间
    ram全局型数组指向内存堆空间对齐后的起始地址
    mem结构体内核附加在各个内存块前面的结构体
    ram_endmem型指针指向系统最后一个内存块
    lfreemem型指针指向当前系统具有最低地址的空闲内存块
    mem_sem信号量用户保护内存堆的互斥信号量,暂未用到
    //附加在每个内存块的顶部
    struct mem{
        mem_size_t next;//相对于内存堆起始地址的偏移
        mem_size_t prev;
        u8_t used;//该内存块是否被分配
    };
    
    void mem_init(void);
    void *mem_malloc(mem_size_t size);
    void mem_free(void rmem);
    static void plug_holes(struct mem *mem);
    void *mem_calloc(size,num);//申请指定大小且初始化为0的空间
    void *realloc();//参数必须是mem_malloc()的返回值,留下指定长度,剩余的插入到空闲块链表,只能减小已分配空间的长度
    

  • lwip中的其他内存管理机制

2. 数据包管理
  • LWIP的层次结构与编程模型

    • 数据链路层:完成IP数据包在物理线路传输时的封装、传递问题

    • 网络层:完成数据包选路和路由,负责将数据包从源主机发送到目标主机

    • 传输层:完成数据在两台主机间的端到端传递,通过识别端口号来向不同的用户程序递交数据

    • lwip没有严格遵循分层,避免数据拷贝的时间开销和内存开销

    • 协议进程模型即实现具体协议栈需要几个进程:

      1. 单进程模型,每个模块独立成为一个进程,灵活但是效率低
      2. 协议栈驻留在操作系统中,协议栈内部各层之间不会有明显的分层界限,可以采用一定的交叉编程技术提高协议栈的执行效率

      lwip的协议栈内核同操作系统内核相互隔离,整个协议栈作为操作系统中的一个单独的进程而存在。用户应用程序可以驻留在协议栈内核的进程中(回调函数,raw/callback API),也可以实现为一个单独的进程(协议栈中 的操作系统模拟层提供的信号量与消息邮箱机制,实现用户进程和协议栈内核进程的数据交互,可以使用sequential API 和socket API)。

      优点:协议栈可以在任何操作系统上移植

      缺点:需要操作系统调度,实时性会受到影响,嵌入式系统中,最好将lwip进程优先级设为最高,以提高实时性。

  • 数据包管理结构pbuf

    lwip的数据包管理核心,能像海纳百川似的兼容各种类型的数据,又能避免各层之间的数据拷贝。

    struct pbuf
    {
        struct pbuf *next;
        void *payload;//指向pubf所记录的数据区域
        u16_t tot_len;//当前pbuf及其后续所有pbuf中包含的有效数据总长度
        u16_t len;//当前pbuf的有效数据长度
        u8_t type;//当前pbuf的类型
        u8_t flags;//状态位,未用到
        u16_t ref;//指向该pbuf的指针数,即该pbuf被引用的次数
    };
    
    //offset 各层的首部长度之和,tcp首部,ip首部,以太网帧首部等
    
    typedef enum
    {
        PBUF_RAM,//pbuf描述的数据在pbuf结构之后的连续内存堆中
        PBUF_ROM,//pbuf描述的数据在ROM中
        PBUF_REF,//pbuf描述的数据在RAM中,但位置与pbuf结构所处位置无关
        PBUF_POOL,//pbuf结构与其描述的数据处于同一内存池中
    }pbuf_type;
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DRZ2EJ6H-1639565346470)(D:notes嵌入式网络那些事lwip.assetsimage-20211129141035451.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6GZVNi4s-1639565346470)(D:notes嵌入式网络那些事lwip.assetsimage-20211129141102440.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J8DQfG6O-1639565346472)(D:notes嵌入式网络那些事lwip.assetsimage-20211129141118875.png)]

  • 数据包管理相关操作函数

    struct pbuf *pbuf_alloc(pbuf_layer layer,u16_t length,pbuf_type type);
    
    #define PBUF_TRANSPORT_HLEN 20 //TCP报文首部长度
    #define PBUF_IP_HLEN		20 //IP数据报首部长度
    
    typedef enum
    {
        PBUF_TRANSPORT,//传输层
        PBUF_IP,//网络层
        PBUF_link,//链路层
        PBUF_RAW//原始层,不预留
    }pbuf_layer;
    
    //成功删除的pbuf个数
    u8_t pbuf_free(struct pbuf *p);
    
3. 网络接口管理
  • 网络接口管理的作用

    • 数据链路层的部分,旨在对具体网络硬件(网卡,串口,环回接口等)、软件进行统一的封装,并为协议栈上层(IP层)提供统一的接口服务。
  • 网络接口结构netif

    #define NETIF_MAX_HWADDR_LEN	6U	//mac地址长度
    #define NETIF_FLAG_UP			0x1U//网络接口是否已被山层使能
    #define NETIF_FLAG_BROADCAST	0x2U//网络接口是否支持广播
    #define NETIF_FLAG_POINTTOPOINT	0x4U//网络接口是否属于点到点连接
    #define NETIF_FLAG_DHCP			0x8U//网络接口是否支持DHCP功能
    #define NETIF_FLAG_link_UP		0x10U//网络接口的底层链路是否已经使能
    #define NETIF_FLAG_ETHARP		0x20U//网络接口是否支持ARP功能
    #define NETIF_FLAG_IGMP			0x40U//网路接口是否支持IGMP功能
    
    struct netif
    {
        struct netif *next;
        struct ip_addr ip_addr;
        struct ip_addr netmask;
        struct ip_addr gw;
        err_t (*input)(struct pbuf *p,struct netif *inp);//向ip层输入数据包
        err_t (*output)(struct netif *netif,struct pbuf *p,struct ip_addr *ipaddr);//发送ip数据包
        err_t (* linkoutput)(struct netif *netif,struct pbuf *p);//实现底层数据包发送
        void *state;//用户自由设置,可以指向底层设备的相关信息
        u16_t mtu;//该接口允许的最大数据包长度
        u8_t hwaddr_len;//mac地址长度
        u8_t hwaddr[NETIF_MAX_HWADDR_LEN];//mac地址
        u8_t flags;//该接口的状态属性字段
        char name[2];
        u8_t num;//接口编号
        struct pbuf *loop_first;//指向发送给自己的数据包的第一个pbuf
        struct pbuf *loop_last;//指向发送给自己的数据包的最后一个pbuf
    };
    
  • 环回接口的概念及作用

    • 根据惯例,ip地址为127.0.0.1
    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OuWN7ucl-1639565346472)(D:notes嵌入式网络那些事lwip.assetsimage-20211201135047642.png)]
4. ARP协议
  • ARP协议的原理

    • 使用目标主机的IP地址,查询其对应的MAC地址
    • ARP缓存表,
  • ARP缓存表及其创建、维护、查询

    • ARP请求包,通过以太网广播的形式发送
    • ARP应答包,收到ARP请求的主机会比对IP地址,如果匹配则返回一个应答包
    • 系统初始化时,ARP缓存表为空,一般会广播自己的地址信息,称为无回报ARP请求
    • 查询ARP缓存表失败,会将要发送的IP数据包挂接在ARP缓存表项后的数据包缓冲队列中,同时广播一个ARP请求包
    • 源主机收到ARP应答包,会提取,更新自身的ARP表,如果该表项的缓冲队列上有未发送的数据,相应的数据会被发送出去
    • 由于网络硬件状态可能随时发生改变,ARP协议需要采用一定的定时机制保证缓存表项的有效性
    • ARP表更新手段:1.主机A向B发送ARP请求,B可以在响应A之前将A的信息放在自己的ARP缓存表中;2.ARP请求是以广播的形式进行的,所有收到ARP请求的主机都可以记录下A的信息,但只有B才会发送ARP应答包;3.无回报请求包同2;4. 收到包含IP数据包的以太网帧,可以提取其中的mac和ip地址信息,加入到缓存表中
    • ARP请求获得的不一定是目标主机真实MAC地址,也可能是一台可以通往局域网外的路由器的MAC地址,在数据包转发的最后一步,必将经过最后一条物理线路到达目的站,发送主机这时必将目的主机IP映射为目标MAC地址
  • ARP报文结构

    struct etharp_q_entry
    {
        struct etharp_q_entry *next;
        struct pbuf *p;
    };
    
    enum etharp_state
    {
        ETHARP_STATE_EMPTY = 0,//初始化状态
        ETHARP_STATE_PENDING,//只记录了ip地址,可能是发出来arp请求包,尚未接收到响应包,超时10s后删除
        ETHARP_STATE_STABLE//定时20min删除,如果下次需要重新发送arp请求包
    };
    
    struct etharp_entry
    {
    
        struct etharp_q_entry *q;//数据包缓冲队列
    
        struct ip_addr ipaddr;//目标IP地址
    
        struct eth_addr ethaddr;//MAC地址
    
        enum etharp_state state;//描述该entry的状态
    
        u8_t ctime;//描述该entry的时间信息
    
        struct netif *netif;//对应网络接口信息
    
    };
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EHJpJUZ5-1639565346473)(D:notes嵌入式网络那些事lwip.assetsimage-20211202134948051.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XG4hPKTC-1639565346474)(D:notes嵌入式网络那些事lwip.assetsimage-20211202140008245.png)]

    • 以太网帧类型:ARP包(0x0806),IP数据包(0x0800),PPPoE(0x8866)
    • 硬件类型:表示发送方想要知道的硬件接口类型,对于以太网mac地址,值为1
    • 协议类型:表示要映射的协议地址类型,为0x0800
    • 硬件地址长度:即mac地址长度
    • 协议地址长度:即ip地址为4
    • 操作字段op:指出数据包的类型,ARP请求(1),ARP应带(2),ARAP请求(3),RARP应答(4)
  • ARP层数据包输入

    static void ethernetif_input(struct netif *netif);
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KZlSh8vD-1639565346475)(D:notes嵌入式网络那些事lwip.assetsimage-20211202145001672.png)]

  • ARP层数据包的发送

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3zMx1sPW-1639565346477)(D:notes嵌入式网络那些事lwip.assetsimage-20211202151302048.png)]

5. 网际协议
  • IP地址及其分类,特殊IP地址

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aX7NPU1b-1639565346478)(D:notes嵌入式网络那些事lwip.assetsimage-20211206105722901.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Qv6WsRVG-1639565346479)(D:notes嵌入式网络那些事lwip.assetsimage-20211206173909400.png)]

    特殊IP地址:

    • 环回地址:127.x.x.x,通常为127.0.0.1,数据包输出到系统的环回接口;

    • 网络地址:标识属于同一个网络的主机或网络设备的集合,路由器只对网络地址匹配的数据包进行转发;

    • 直接广播地址:主机号全部为1的IP地址,代表本网络内的所有网络设备;

    • 受限广播地址:IP地址32位全为1,即255.255.255.255,代表本地受限广播,属于E类地址

    • 本网络上的特定主机:可以将网络地址对应字节全部设置为0进行简化,属于A类地址

    • 本网络本主机:IP地址32位全为0,即0.0.0.0,通常用于某个主机启动时,需要通信,但暂时不知道自己的IP地址,属于A类地址

  • 子网划分,子网掩码,NAT等概念

    将主机号再划分为一个子网号和主机号(通常出现在A类和B类地址中)。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CrmnXP6j-1639565346480)(D:notes嵌入式网络那些事lwip.assetsimage-20211207111430921.png)]

    划分子网的好处:

    • 减少标准IP编址中地址浪费现象
    • 节省通信流量(通信流量与主机的数量成正比)
    • 主机数减少,使得主机管理更加方便

    子网掩码:网络位全为1(包括子网位),主机位全为0;

    网络地址转换(NAT):IP地址短缺 局域网技术 专用网

    • 具有NAT功能的路由器,至少需要一个内部端口(与局域网内用户通信,使用一个内部专用IP地址,常见的192.168.1.1)和一个外部端口(与外部网络通信,通常具有一个有效的IP地址,假设为一个有效的C类地址222.197.179.21)

    • 内部用户联网时,将内部IP地址转换成外部公共的IP地址,反之数据返回时,将目的IP地址转换成内部IP地址

    • 端口多路复用:基于TCP或UDP协议端口号以及IP地址来实现NAT功能

      例:局域网内用户192.168.1.78使用TCP协议与Internet中的一个HTTP服务器(130.21.45.20,80)进行通信:

      • (192.168.1.78,1234,130.21.45.20,80)到路由器,路由器会为其一个内部的NAT端口(假设为5678),同时路由器转发该分组时,会修改源IP地址和端口号为(222.197.179.21,5678,130.21.45.20,80)
      • 路由器接收到(130.21.45.20,80,222.197.179.21,5678)分组后,会在NAT表中查找5678的连接,并把分组中的目的IP地址和端口信息改为NAT表中记录的信息,即(130.21.45.20,80,192.168.1.78,1234)

    单播、多播与广播:

    • 多播是D类地址,判断其IP地址的最高4位是否为1110
    • 在以太网组播(多播)数据帧发送时,直接将MAC地址的低23位设置为目的多播IP地址的低23位
    • 广播地址分为直接广播和受限广播
    • 如果一个数据既不是多播也不是广播,就是单播了
  • IP层数据报结构以及数据报输入处理

    • IP层的数据包,叫做IP数据报或IP分组

    • 格式:

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vkI7eAGw-1639565346482)(D:notes嵌入式网络那些事lwip.assetsimage-20211208090135566.png)]

      • 版本号:对于IPv4,为4,对于IPv6,为6

      • 首部长度:长度以字(4Bytes)为单位,对于不含任何选项字段的IP首部,该值为5,能描述的最大长度为15*4=60Byte

      • 服务类型:描述当前IP数据报急需的服务类型,如最小延时,最大吞吐量,最高可靠性,最小费用等。路由器在转发数据报时,可以根据该值选择最合理的路由路径

      • 总长度:整个IP数据报的总长度,理论上最大可达65535字节,但是以太网数据帧中的数据最长为1500字节(MTU)。IP层会检查底层设备的MTU,进行分片再递交给底层发送。

      • 16位标识字段:用于标识IP层发送出去的每一份IP数据报,每发送一份报文,该值加1,数据报被分片时,该字段会被复制到每一个分片中。接收端根据该字段组装分片

      • 3位标志字段:第一位保留;第二位是不分片位,被置位时,数据报在发送或转发过程中不能被分片,如果数据报太大,则会被丢弃;第三位表示更多分片位,被置位时,说明该分片不是最后一个分片,为0则说明该分片时最后一个分片或者唯一的分片

      • 13位分片偏移量:表示当前分片所携带的数据在数据报中的相对位置(以8字节为单位),分片会被单独传输

      • 生存时间:描述该IP数据报最多能被转发的次数,每转发一次,该值减1,为0时,路由器会丢弃分组,同时一个ICMP差错报文会被返回至源主机,保证数据不会在网络中无休止的飘荡

      • 8位协议字段:描述该IP数据报中的数据是来自于哪个上层协议,为1表示ICMP协议,为2表示IGMP协议,为6表示TCP协议,为17表示UDP协议

      • 16位首部校验和只针对IP首部做校验,数据的校验由上层协议负责

      • 二进制反码求和

        • 对两个二进制数直接进行加法运算
        • 求和规则:0+0=0,0+1=1,1+1=0(进位加到下一位)
        • 若最高位相加仍产生进位,需要在最后的结果中加1
        • 对最后结果取反码
      • 选项字段:最长可达40字节,且大小必需是4的整数倍,否则需要用0填充,lwip对选项字段只识别不处理

      • 数据结构

        // __attribute__ 关键字主要用来在函数或数据声明中设置其属性
        //__attribute__((attribute-list))   其位置约束:放于声明的尾部“;”之前
        //__attribute__((packed)):告诉编译器取消结构在编译过程中的优化对齐,即按字节对齐
        struct ip_hdr 
        {
            u16_t _v_hl_tos;
            u16_t _len;
            u16_t _id;
            u16_t _offset;
            #define IP_RF	0x0800
            #define IP_DF	0x4000
            #define IP_MF	0x2000
            #define IP_OFFMASK	0x1FFF
            u16_t _ttl_proto;
            u16_t _chksum;
            struct ip_addr src;
            struct ip_addr dest;
            
        };//必须禁止编译器的自对齐
        
  • IP层数据报的发送及分片处理

    //根据目的IP地址查找合适的网络接口,并调用函数ip_output_if完成最终的发送工作
    err_t ip_output(struct pbuf *p,struct ip_addr *src,struct ip_addr *dest,u8_t ttl,u8_t tos,u8_t proto);
    
    //填写IP首部中的各个字段值,并发送数据报,组装好数据包后,判断目的IP地址的情况
    //1.如果是本地的地址,直接调用环回接口数据报发送函数netif_loop_output
    //2.网络接口的mtu不为0,且数据报长度大于mtu,需要对数据报进行分片,调用ip_frag
    //3.如果前两种情况都不是调用网卡结构注册的output函数完成发送工作
    err_t ip_output_if(struct pbuf *p,struct ip_addr *src,struct ip_addr *dest,u8_t ttl,u8_t tos,u8_t proto,struct netif *netif);
    
    //根据目的IP地址选择一个最合适(网口设备与目的IP位于同一个子网)的网络接口结构
    struct netif *ip_route(struct ip_addr *dest);
    
    

    数据报分片:路由器从一个大mtu值的网络上接收数据转发到具有较小mtu值的物理网络上,分片大小是8的整数倍

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wV8NqASG-1639565346483)(D:notes嵌入式网络那些事lwip.assetsimage-20211214162632270.png)]

    err_t ip_frag(struct pbuf *p,struct netif *netif,struct ip_addr *dest);
    
  • IP分片数据的重装过程

    • 数据报接收

      struct netif *current_netif;//指向接收到当前数据报的网络接口结构
      const struct ip_hdr *current_header;//指向当前处理的数据报首部
      err_t ip_input(struct pbuf *p,struct netif *inp);
      

tif *ip_route(struct ip_addr *dest);

数据报分片:路由器从一个大mtu值的网络上接收数据转发到具有较小mtu值的物理网络上,分片大小是8的整数倍

[外链图片转存中...(img-wV8NqASG-1639565346483)]

```c
err_t ip_frag(struct pbuf *p,struct netif *netif,struct ip_addr *dest);
  • IP分片数据的重装过程

    • 数据报接收

      struct netif *current_netif;//指向接收到当前数据报的网络接口结构
      const struct ip_hdr *current_header;//指向当前处理的数据报首部
      
      err_t ip_input(struct pbuf *p,struct netif *inp);
      
      • 数据报分片重装(低版本不支持)
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/667498.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号