bufiox

package
v0.35.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 6, 2026 License: MIT Imports: 3 Imported by: 0

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

Constants

This section is empty.

Variables

View Source
var (
	// ErrNegativeCount 负数长度参数。
	ErrNegativeCount = errors.New("bufiox: 负数长度")
	// ErrNoRemainingData Next/Peek/Skip 请求的数据量超过剩余可用数据。
	ErrNoRemainingData = errors.New("bufiox: 剩余数据不足")
	// ErrTooLarge 请求的长度超出单个缓冲的容量上限。
	ErrTooLarge = errors.New("bufiox: 请求长度超出缓冲上限")
)

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) Next

func (r *BytesReader) Next(n int) ([]byte, error)

Next 实现 Reader。

func (*BytesReader) Peek

func (r *BytesReader) Peek(n int) ([]byte, error)

Peek 实现 Reader。

func (*BytesReader) ReadBinary

func (r *BytesReader) ReadBinary(p []byte) (int, error)

ReadBinary 实现 Reader(拷贝读)。

func (*BytesReader) ReadLen

func (r *BytesReader) ReadLen() int

ReadLen 实现 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])。

func (*BytesReader) Skip

func (r *BytesReader) Skip(n int) error

Skip 实现 Reader。

type BytesWriter

type BytesWriter struct {
	// contains filtered or unexported fields
}

BytesWriter 基于可增长字节切片的 Writer(无底层写出目标)。 适合在内存中组装报文后整体取走。

func NewBytesWriter

func NewBytesWriter(buf []byte) *BytesWriter

NewBytesWriter 返回空 BytesWriter。可传初始 buf 预留容量。

func (*BytesWriter) Bytes

func (w *BytesWriter) Bytes() []byte

Bytes 返回已组装的全部内容(视图,非拷贝)。

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) Buffered

func (r *DefaultReader) Buffered() int

Buffered 返回缓冲中尚未消费的字节数。

func (*DefaultReader) Next

func (r *DefaultReader) Next(n int) ([]byte, error)

Next 实现 Reader。

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) ReadLen

func (r *DefaultReader) ReadLen() int

ReadLen 实现 Reader。

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 攒批。

func (*DefaultWriter) WrittenLen

func (w *DefaultWriter) WrittenLen() int

WrittenLen 实现 Writer。

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,支持零拷贝写。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL