由于网络协议栈是分层的,因此对数据缓冲区提出了以下要求:
能够方便地在头部和尾部添加数据。(下层封装上层数据)
能够方便地从缓存中移出数据。(数据传递给上层时需要移除头部)
尽量减少拷贝。
BSD 给出的答案是 mbuf(memory buffer)。
mbuf 种类
mbuf 的定义如下:
struct m_hdr {
struct mbuf *mh_next;
struct mbuf *mh_nextpkt;
caddr_t mh_data;
int mh_len;
short mh_type; (1)
short mh_flags; (2)
};
struct mbuf { (3)
struct m_hdr m_hdr;
union {
} M_dat;
};
#define m_flags m_hdr.mh_flags
mbuf 中储存的数据类型:
类型 说明 MT_FREE
should be on free list
MT_DATA
dynamic (data) allocation
MT_HEADER
packet header
MT_SOCKET
socket structure
MT_PCB
protocol control block
MT_RTABLE
routing tables
MT_HTABLE
IMP host tables
MT_ATABLE
address resolution tables
MT_SONAME
socket name
MT_SOOPTS
socket options
MT_FTABLE
fragment reassembly header
MT_RIGHTS
access rights
MT_IFADDR
interface address
MT_CONTROL
extra-data protocol message
MT_OOBDATA
expedited data
mbuf 的类型
mbuf 的大小为 128B。
根据 m_flags
的值,mbuf 一共分为四种类型:
m_flags | 作用 |
---|---|
0 | mbuf 只包含数据
|
M_PKTHDR | 分组首部
|
M_EXT | 数据簇
|
M_PKTHDR | M_EXT | 包含了分组首部的数据簇 |
mbuf 的基本结构
mbuf 本是是一个单向链表。其结构为:
mbuf 的分配和释放
mbuf 的分配和释放函数如下:
函数 | 作用 |
---|---|
| 分配一个 mbuf。 |
| 释放 mbuf |
由于 MGET 实际上是一个宏,所以第一个参数类型实际上为
mbuf *m
。
需要注意的时,这两个函数实际上都是宏,但是被改写成了函数形式。MGET 的准确定义为:
#define MGET(m, how, type) \
{ \
MALLOC((m), struct mbuf *, MSIZE, mbtypes[type], (how)); \
if (m) { \
(m)->m_type = (type); \
MBUFLOCK(mbstat.m_mtypes[type]++;) \
(m)->m_next = (struct mbuf *)NULL; \
(m)->m_nextpkt = (struct mbuf *)NULL; \
(m)->m_data = (m)->m_dat; \
(m)->m_flags = 0; \
} else \
(m) = m_retry((how), (type)); \
}