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字节对齐的,这样清零之后总是能获得起始位置。

TCP/IP卷2 - 读书笔记(1) 存储管理,布布扣,bubuko.com

时间: 2024-10-09 21:02:09

TCP/IP卷2 - 读书笔记(1) 存储管理的相关文章

TCP/IP网络编程读书笔记-简单的套接字编程(1)

在linux和windows下都是通过套接字编程进行网络编程.不同的系统上通信有部分差别,现在刚开始学习,给自己学习的时候一个总结. 一,socket函数的套接字步骤 第一,linux网络编程中接受连接请求(服务器端)套接字的四个步骤: 1)调用socket函数创建套接字 2)调用bind函数分配IP地址和端口号 3)调用listen函数转为可接收请求状态 4)调用accept函数受理连接请求 第二,linux网络编程中请求连接(客户端)套接字的两个步骤: 1)调用socket函数创建套接字 2

TCP/IP知识总结(TCP/IP协议族读书笔记二)

接下来,总结一下网络层的协议,IP,ARP,RARP,ICMP,IGMP.当我们在网络传输的过程中,把分组交付到主机或路由器需要两级地址:物理地址和逻辑地址.而且我们需要能够把物理地址映射成为相应的逻辑地址,反过来的映射也是必要的. 这时候就涉及两个概念:静态映射与动态映射. 静态映射就是创建一个表,将逻辑地址与物理地址关联起来,这个表存储在网络的每一个机器上.可是存在于网络中的机器的物理地址是经常会发生改变的(更换网卡),这样静态映射表就得时常更新,影响网络的性能. 动态映射就是每当机器知道其

TCP/IP知识总结(TCP/IP协议族读书笔记四)

参考:http://blog.chinaunix.net/uid-26275986-id-4109679.html 继续!TCP的流量控制和拥塞控制. TCP相对UDP可靠的地方在于它的拥塞控制.流量控制. 一.流量控制: 如果发送方把数据发送得过快,接收方可能会来不及接收,这就会造成数据的丢失.所谓流量控制就是把发送方的发送速率不要太快,要让接收方来得及接收.利用滑动窗口机制可以很方便的在TCP连接上实现对发送方的流量控制.主要的方式就是返回ACK中会包含自己的接受窗口的大小,并且利用大小来控

《TCP/IP详解卷1:协议》第19章 TCP的交互数据流-读书笔记

章节回顾: <TCP/IP详解卷1:协议>第1章 概述-读书笔记 <TCP/IP详解卷1:协议>第2章 链路层-读书笔记 <TCP/IP详解卷1:协议>第3章 IP:网际协议(1)-读书笔记 <TCP/IP详解卷1:协议>第3章 IP:网际协议(2)-读书笔记 <TCP/IP详解卷1:协议>第4章 ARP:地址解析协议-读书笔记 <TCP/IP详解卷1:协议>第5章 RARP:逆地址解析协议-读书笔记 <TCP/IP详解卷1:协

TCP/IP 网络编程 (抄书笔记 1) -- TCP

TCP/IP 网络编程 (抄书笔记 1) – TCP TCP/IP 网络编程 (抄书笔记 1) – TCP Table of Contents server client 更好的 client 端实现 来源: <TCP/IP 网络编程> 抄书: 通信的双方都各自 拥有 输入缓存和输出缓存 socket 的 write 函数并不是立即传输数据, 而是写到输出缓存区, 到达另一端的输入缓存区 socket 的 read 函数调用的瞬间, 就从输入缓存区中读取数据 TCP 协议中的滑动窗口会保证 数

【转】TCP/IP详解学习笔记(二)

TCP/IP详解学习笔记(5)-IP选路,动态选路,和一些细节 1.静态IP选路 1.1.一个简单的路由表 选路是IP层最重要的一个功能之一.前面的部分已经简单的讲过路由器是通过何种规则来根据IP数据包的IP地址来选择路由.这里就不重复了.首先来看看一个简单的系统路由表. Destination     Gateway         Genmask         Flags Metric Ref    Use Iface192.168.11.0    *               255.

TCP/IP详解学习笔记

TCP/IP详解学习笔记(1)-基本概念 TCP/IP详解学习笔记(2)-数据链路层 TCP/IP详解学习笔记(3)-IP协议,ARP协议,RARP协议 TCP/IP详解学习笔记(4)-ICMP协议,ping和Traceroute TCP/IP详解学习笔记(5)-IP选路,动态选路,和一些细节 TCP/IP详解学习笔记(6)-UDP协议 TCP/IP详解学习笔记(7)-广播和多播,IGMP协议 TCP/IP详解学习笔记(8)-DNS域名系统 TCP/IP详解学习笔记(9)-TCP协议概述 TCP

TCP/IP 网络编程 (抄书笔记 2) -- UDP

TCP/IP 网络编程 (抄书笔记 2) – UDP TCP/IP 网络编程 (抄书笔记 2) – UDP Table of Contents server client connect 来源: <TCP/IP 网络编程> 抄书: TCP 协议若要向 10 个客户端提供服务, 除了需要 listen 套接字外, 还需要 10 个服务器端套接字 (accept), 但是在 UDP 中, 不管是服务器端还是客户端都只需要 1 个套接字 udp 的 client 不需要 bind, 调用 sendt

TCP/IP 网络编程 (抄书笔记 4) -- 管道: 进程间通信

TCP/IP 网络编程 (抄书笔记 4) – 管道: 进程间通信 TCP/IP 网络编程 (抄书笔记 4) – 管道: 进程间通信 int fds[2]; pipe(fds); write(fds[1], buf, strlen(buf)); read(fds[0], buf, BUF_SIZE); 如果两个进程的通信只是 单纯的一方写, 然后另一方读 的情况, 那么 我们的管道操作没有问题, 但是: char str1[] = "str1"; char str2[] = "