Documentation
¶
Overview ¶
Package bufiox 面向协议编解码的缓冲 IO:读侧 Next/Peek/Skip 返回内部缓冲的 零拷贝视图(省去逐字段拷贝),写侧 Malloc/WriteBinary 攒批后一次 Flush (零拷贝引用调用方切片)。典型用法是在自定义二进制协议解析中,先 Peek 定长 头、按长度字段 Next 出负载视图,解析全程零拷贝,最后 Release 归还。
错误约定:
- Next/Peek/Skip 数据不足返回 ErrNoRemainingData(底层读错误原样透出);
- ReadBinary 按经典 io 语义:读满 (len(bs), nil)、部分读 (n, io.ErrUnexpectedEOF)、 无数据 (0, io.EOF);
- Release 后 Next/Peek 返回的视图全部失效(缓冲被重置)。
与 bufio 的区别:bufio.Read 必须拷贝进调用方切片;本包的读路径可以把缓冲区 视图直接交给调用方,Write 路径可以引用调用方内存攒批。与标准库 bytes 包的 Reader/Writer 的区别:本包面向流(io.Reader/io.Writer 适配)并带 Release 生命周期。
设计参考 cloudwego/gopkg/bufiox(Apache-2.0),本实现为独立重写(MIT, oekit/pkg):接口语义一致;去掉了对 bytedance/gopkg mcache/dirtmake 的依赖, 缓冲改用普通分配(GC 回收,无池化归还需要跟踪)。
Index ¶
- Variables
- type BytesReader
- type BytesWriter
- type DefaultReader
- func (r *DefaultReader) Buffered() int
- func (r *DefaultReader) Next(n int) ([]byte, error)
- func (r *DefaultReader) Peek(n int) ([]byte, error)
- func (r *DefaultReader) Read(bs []byte) (n int, err error)
- func (r *DefaultReader) ReadBinary(bs []byte) (int, error)
- func (r *DefaultReader) ReadLen() int
- func (r *DefaultReader) Release(e error) error
- func (r *DefaultReader) Skip(n int) error
- type DefaultWriter
- type Reader
- type Writer
Constants ¶
This section is empty.
Variables ¶
Functions ¶
This section is empty.
Types ¶
type BytesReader ¶
type BytesReader struct {
// contains filtered or unexported fields
}
BytesReader 基于一段既有字节切片的 Reader(只读,不修改 buf)。 适合解析已整体收包的帧。
func NewBytesReader ¶
func NewBytesReader(buf []byte) *BytesReader
NewBytesReader 返回读取 buf[:len(buf)] 的 BytesReader。
func (*BytesReader) ReadBinary ¶
func (r *BytesReader) ReadBinary(p []byte) (int, error)
ReadBinary 实现 Reader(拷贝读)。
func (*BytesReader) Release ¶
func (r *BytesReader) Release(e error) error
Release 实现 Reader。
- e == nil:回到起点(游标归零、ReadLen 归零),buf 引用保留——本类型 面对的是「已整体收包的固定帧」,重新解析同一帧是它的常见用法。
- e != nil:**整段丢弃**,buf 引用清空,此后读取返回 ErrNoRemainingData。
与 DefaultReader 的差异不是随意为之:那边面对的是可续读的流,残留字节既 无法重读、又可能是下一条报文的开头,所以 e==nil 时保留残留;而固定帧「重置」 的自然含义就是回到起点。两者的共同点是 e != nil 一律丢弃([#216])。
type BytesWriter ¶
type BytesWriter struct {
// contains filtered or unexported fields
}
BytesWriter 基于可增长字节切片的 Writer(无底层写出目标)。 适合在内存中组装报文后整体取走。
func NewBytesWriter ¶
func NewBytesWriter(buf []byte) *BytesWriter
NewBytesWriter 返回空 BytesWriter。可传初始 buf 预留容量。
func (*BytesWriter) Flush ¶
func (w *BytesWriter) Flush() error
Flush 实现 Writer:无底层写出目标,仅重置计数;已写内容保留在 buf。
func (*BytesWriter) Malloc ¶
func (w *BytesWriter) Malloc(n int) ([]byte, error)
Malloc 实现 Writer:在 buf 尾部申请 n 字节零值空间并返回视图。
func (*BytesWriter) WriteBinary ¶
func (w *BytesWriter) WriteBinary(bs []byte) (int, error)
WriteBinary 实现 Writer:拷贝追加 bs(内存组装场景零拷贝无意义)。
func (*BytesWriter) WrittenLen ¶
func (w *BytesWriter) WrittenLen() int
WrittenLen 实现 Writer:自上次 Flush 起累计写入的字节数。
type DefaultReader ¶
type DefaultReader struct {
// contains filtered or unexported fields
}
DefaultReader 基于任意 io.Reader 的缓冲 Reader。 Next/Peek 返回内部缓冲的零拷贝视图;视图在 Release 之前始终有效 (内部缓冲扩容时旧缓冲整体保活,不会原地搬移破坏已返回的视图)。
func NewDefaultReader ¶
func NewDefaultReader(rd io.Reader) *DefaultReader
NewDefaultReader 返回从 rd 读取的 DefaultReader(默认 8KiB 起步缓冲)。
func NewDefaultReaderSize ¶
func NewDefaultReaderSize(rd io.Reader, size int) *DefaultReader
NewDefaultReaderSize 返回从 rd 读取、缓冲至少 size 字节的 DefaultReader。
func (*DefaultReader) Peek ¶
func (r *DefaultReader) Peek(n int) ([]byte, error)
Peek 实现 Reader;数据不足时尽量返回缓冲中已有的部分视图 + 错误。
func (*DefaultReader) Read ¶
func (r *DefaultReader) Read(bs []byte) (n int, err error)
Read 实现 io.Reader:缓冲有存量时只返回存量(不等满),语义区别于 ReadBinary。
func (*DefaultReader) ReadBinary ¶
func (r *DefaultReader) ReadBinary(bs []byte) (int, error)
ReadBinary 实现 Reader:先拷贝缓冲存量,缺口大(≥ 4KiB)时直接读入 调用方切片省一次中转拷贝,小缺口走 acquire 缓冲后拷贝。
func (*DefaultReader) Release ¶
func (r *DefaultReader) Release(e error) error
Release 实现 Reader。
两种情形([#216]):
- e != nil:**整段丢弃**。缓冲置空、游标归零——连接层错误意味着残留字节 已不可信(可能是半包、可能是上一个连接的尾巴),留着只会被当数据用。
- e == nil:**保留未消费残留**并把游标归零。socket 上已经读出的字节无法 重读,丢弃就是丢数据;而残留恰恰可能是下一个报文的开头(同一 TCP 段里 常含多条消息),这正是本类型存在的理由。
两种情形都会清掉终态错误(下一个读取周期重新感知底层状态,与 bufio.Reset 同口径)、把 ReadLen 归零、并归还零拷贝视图的保活引用。
关于「视图失效」:Release 之后调用方**一律不得**再使用此前 Next/Peek 返回的 视图。但请注意这是**契约要求**,不是运行时保证——Go 里被「释放」的切片不会 变成野指针,读它不会 fault,只会读到已不属于你的字节。e == nil 且游标非零时 残留会被原地左移,旧视图指向的区域正是被覆盖的位置(内容已变);残留远小于 容量时还会有换小数组的收缩,旧底层数组随之可回收。
func (*DefaultReader) Skip ¶
func (r *DefaultReader) Skip(n int) error
Skip 实现 Reader:先消费缓冲,不足部分用小缓冲直接从底层丢弃。
type DefaultWriter ¶
type DefaultWriter struct {
// contains filtered or unexported fields
}
DefaultWriter 基于任意 io.Writer 的缓冲 Writer:Malloc 段与零拷贝引用段 按调用顺序攒批,Flush 经 net.Buffers 写出(对 net.Conn 自动走 writev)。
func NewDefaultWriter ¶
func NewDefaultWriter(wd io.Writer) *DefaultWriter
NewDefaultWriter 返回写入 wd 的 DefaultWriter。
func (*DefaultWriter) Flush ¶
func (w *DefaultWriter) Flush() error
Flush 实现 Writer:net.Buffers.WriteTo 对 net.Conn 走 writev,普通 io.Writer 逐段写。写出失败错误粘滞,后续 Malloc/WriteBinary/Flush 直接返回。
func (*DefaultWriter) Malloc ¶
func (w *DefaultWriter) Malloc(n int) ([]byte, error)
Malloc 实现 Writer。
func (*DefaultWriter) WriteBinary ¶
func (w *DefaultWriter) WriteBinary(bs []byte) (int, error)
WriteBinary 实现 Writer:≥ 4KiB 零拷贝引用,小切片拷入当前 chunk 攒批。
type Reader ¶
type Reader interface {
// Next 顺序读出接下来 n 字节,返回长度为 n 的视图 p;
// 数据不足时返回错误。p 可能是底层缓冲的浅拷贝视图,
// 调用方在 Release 之前不得修改、之后不得继续使用 p。
Next(n int) (p []byte, err error)
// ReadBinary 读取至多 len(p) 字节填满 p,返回读到的字节数。
// 拷贝读:p 在 Release 之后仍然有效。
// 语义:读满返回 (len(p), nil);部分读返回 (n, io.ErrUnexpectedEOF);
// 无数据可读返回 (0, io.EOF)。
ReadBinary(p []byte) (n int, err error)
// Peek 行为同 Next,但不推进读位置(随后可 ReadBinary/Skip 消费)。
// 返回视图的生命周期约束同 Next。
Peek(n int) (buf []byte, err error)
// Skip 跳过接下来 n 字节;数据不足时返回错误。
Skip(n int) (err error)
// ReadLen 返回自上次 Release 以来累计消费的字节数
// (Next/ReadBinary/Skip 累加,Release 归零)。
ReadLen() (n int)
// Release 结束本轮读取:归还零拷贝视图的保活引用、把 ReadLen 归零、
// 清掉终态错误(下一个读取周期重新感知底层状态)。
//
// 参数 e 决定**未消费数据**的去留([#216]):
//
// - e != nil:整段丢弃。连接层错误意味着残留字节已不可信(半包、或
// 上一个连接的尾巴),留着只会被当成数据用。
// - e == nil:去留由实现定义——因为「重置」对可续读的流与固定帧含义
// 不同。DefaultReader 保留残留并把游标归零(socket 上已读出的字节
// 无法重读,且残留可能是下一条报文的开头);BytesReader 回到起点
// (固定帧,重新解析是常见用法)。见各实现的 Release 文档。
//
// 视图约束:Release 之后调用方**一律不得**再使用此前 Next/Peek 返回的
// 视图。注意这是契约要求而非运行时保证——Go 里被「释放」的切片不会变成
// 野指针,读它不 fault,只会读到已不属于你的字节。
//
// Release 不关闭底层连接,只归还用户态缓冲。
Release(e error) (err error)
}
Reader 是缓冲读接口:用户态零拷贝读,降低内存分配与拷贝开销。
type Writer ¶
type Writer interface {
// Malloc 申请 n 字节写缓冲并返回视图,调用方填入数据;
// Flush 之前对返回 buf 的写入都是暂存的,Flush 后不得再写入。
Malloc(n int) (buf []byte, err error)
// WriteBinary 追加 bs;可能是零拷贝写(Flush 之前不得修改 bs)。
// 写入不足 len(bs) 时返回错误,n 为已写入字节数。
WriteBinary(bs []byte) (n int, err error)
// WrittenLen 返回自上次 Flush 以来累计写入的字节数
// (Malloc/WriteBinary 累加,Flush 归零)。
WrittenLen() (length int)
// Flush 把攒批的数据写到底层目标,并重置 WrittenLen。
Flush() (err error)
}
Writer 是缓冲写接口:用户态攒批 + 一次性 Flush,支持零拷贝写。