在 Go 语言网络编程里,服务端和客户端常常通过 TCP 或 UDP 收发没有文本格式的二进制数据。直接对 []byte 做移位运算不仅容易出错,而且代码可读性差。标准库中的 encoding/binary 包提供了稳定且高效的工具,用于在不同字节序下编解码数值与结构体。

为什么用 encoding/binary
手动解析原始字节流时,开发者要关心平台的大小端差异,还要计算偏移量。encoding/binary 通过 binary.ByteOrder 统一处理这些问题,并可以和 io.Reader、io.Writer 无缝配合。
常用字节序
- binary.BigEndian:网络协议常用的大端序
- binary.LittleEndian:部分硬件和本地文件格式使用的小端序
基础用法示例
下面展示如何把一个头部结构体写入连接,并从连接读回。
package main
import (
"bytes"
"encoding/binary"
"fmt"
)
type Header struct {
Version uint8
Length uint32
}
func main() {
var buf bytes.Buffer
h := Header{Version: 1, Length: 1024}
// 以大端序写入结构体
err := binary.Write(&buf, binary.BigEndian, &h)
if err != nil {
panic(err)
}
fmt.Println("encoded bytes:", buf.Bytes())
// 从字节流读回结构体
var decoded Header
readErr := binary.Read(&buf, binary.BigEndian, &decoded)
if readErr != nil {
panic(readErr)
}
fmt.Printf("decoded: %+vn", decoded)
}
处理变长负载
很多协议采用“头部长度字段 + 负载”的形式。先读头部,再根据 Length 分配切片读取剩余数据,可避免粘包导致的解析错误。
func readMessage(conn interface {
Read([]byte) (int, error)
}) (Header, []byte, error) {
var h Header
// 假设 conn 已封装好,这里仅示意读取头部
hdrBuf := make([]byte, 5)
if _, err := conn.Read(hdrBuf); err != nil {
return h, nil, err
}
h.Version = hdrBuf[0]
h.Length = binary.BigEndian.Uint32(hdrBuf[1:5])
payload := make([]byte, h.Length)
if _, err := conn.Read(payload); err != nil {
return h, nil, err
}
return h, payload, nil
}
注意事项
使用 binary.Read 和 binary.Write 时,结构体字段必须是固定大小的类型,不能包含 slice 或 map。变长内容需单独读写。若协议中有字符串,建议以长度前缀加原始字节方式传输,再用 string() 转换。
在跨平台通信中,始终明确指定 ByteOrder,不要依赖本地字节序,否则会出现难以排查的兼容问题。
小结
通过 encoding/binary,可以用极少代码完成可靠的字节流解析。配合 io.ReadFull 等函数,能写出健壮的网络协议处理层。
Goencoding_binary网络字节流修改时间:2026-07-27 10:33:18