zoukankan      html  css  js  c++  java
  • TCP/IP卷2 读书笔记(1) 存储管理 曹超

     
      最近在看TCP/IP的BSD实现。首先是它的存储管理,主要是通过mbuf这个结构体来管理缓存。看了一部分,觉得设计的很好,把大块的数据拆成小块存储,这样能很方便的写回收池。之前在写流媒体服务器时,一直苦恼对应帧数据大内存管理,分配的内存之后,该怎么回收,最后是模仿nginx的内存池,再每块固定大小的内存块前面加上了引用计数,再把这块内存分块分配,最后引用计数为0时再回收到池。
     
      看了TCP/IP的缓存管理,觉得把帧数据打散存在固定大小的mbuf里,最后统一回收这块固定大小的结构块就可以了,也是一种方法。
    下面来看看mbuf的实现。
     
    一:结构体

    mbuf的头部信息

    struct m_hdr {
           struct mbuf *mh_next; /* 指向链中下一个mbuf的指针 */
           struct mbuf *mh_nextpkt; /* 指向下一个链的指针 */
           int mh_len; /* mbuf中数据的长度(不包括头部) */
           char *mh_data; /* 指向数据区的指针 */
           short mh_type; /* mbuf的数据类型,如MT_DATA*/
           short mh_flags; /* mbuf标识,具体定义见下 */
    };
     
    mbuf标识
    #define M_EXT 0x0001 /*使用簇作为外部换成  */
    #define M_PKTHDR 0x0002 /* 指示mbuf包含的是一个分组首部 */
    #define M_EOR 0x0004 /* 分组结束,一般哟哟与OSI协议,TCP从来不用这个标志,因为TCP是流协议,没有边界的*/
     
    struct pkthdr {
           int len; /* 整个mbuf链表包含数据的总长度,在链表的第一个mbuf中维护一个带有总长度的分组首部的原因是,当需要总长度时可以避免查看所有mbuf中的mh_len来求和*/
           struct ifnet *rcvif; /* 指向接收分组的接收接口结构的指针*/
    };
     
    这里使用共用体来描述,依赖于m_type的类型来决定共用体的内容。这个可以学习。
    struct mbuf {
           struct m_hdr m_hdr;
           union {
                  struct {
                         struct pkthdr MH_pkthdr; /* M_PKTHDR set */
                         union {
                                struct m_ext MH_ext; /* M_EXT set */
                                char MH_databuf[MHLEN];
                         } MH_dat;
                  } MH;
                  char M_databuf[MLEN]; /* !M_PKTHDR, !M_EXT */
           } M_dat;
    };
     
    并且最后定义了几个宏来简化结构体的操作,这个也可以学习下。
    比如:
    #define m_next m_hdr.mh_next
    #defiene m_dat M_dat.M_databuf
     
    mbuf的数据结构如下:
    依靠m_next来组成一个分组。
    依靠m_nextpkt组成多个分组。
     
     
    二:添加IP和UDP首部
     
        在mbuf中添加协议首部也很方便,只需要再分配一个mbuf,并把它添加到链首。这里是将IP与UDP首部28个字节放在mbuf的数据区的底部,这样底层协议可以
    很方便的在上面继续增加协议头。
     
    三:输入是如何防止异步导致的数据结构被破坏
    数据输入是异步的,网卡驱动程序接收到一个中断,内核就会调用设备驱动来处理这个分组,这样mbuf由于在两个协议层之间是数据共享的,所以中断触发的时候就有可能破坏数据结构。
    Net/3的代码是通过调整中断优先级来保护共享数据的。网络协议处理是软中断,级别低于网络设备的输入输出中断,当网络设备驱动程序完成之后,会把接收到的分组放置到IP队列中,然后出发协议处理软中断。
     
    比如正道IP协议层来处理输入分组时,它会去检查链表中是否有数据:
    struct mbuf *m;
    int s;
    s = splimp(s);
    IF_DEQUEUE(&ipring,m)
    splx(s);
    if(m == 0)
    return;
     
    splimp是把cpu的优先级升高到跟网路设备驱动程序级别,防止任何网络设备驱动程序中断发生。
    splx是恢复之前的优先级。
     
     
    三:dtom宏
     
    #define dtom(x) (struct mbuf*)((int)x & ~(MSIZE -1))   MSIZE是mbuf的大小,32位下为128位。
    这个宏实现了将一个存放在mbuf中任意位置的数据转换成mbuf,当时一直没看懂,这个宏怎么能实现把结构体成员转成结构体指针,如果说是offset这个宏,还能明白。这个宏主要就是将地址的地位清零来获取起始位置,
    后来觉得是因为mbuf总是128字节对齐的,这样清零之后总是能获得起始位置。
     
     
     
     
     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    2020 商业计划书
    LBDP数据采集网关的设计要求
    Net学习日记_ASP.Net_Ajax
    Net学习日记_ASP.Net_WebForm_笔记
    Net学习日记_ASP.Net_WebForm
    Net学习日记_ASP.Net_一般处理程序_笔记
    Net学习日记_ASP.Net_一般处理程序
    Net学习日记_聊天室(基于Socket,Thread)_服务器软件
    Net学习日记_聊天室(基于Socket,Thread)
    Net学习日记_泛型与反射_笔记
  • 原文地址:https://www.cnblogs.com/caochao/p/3905705.html
Copyright © 2011-2022 走看看