必须用binary.bigendian,因为网络字节序即大端序,tcp/ip、dns、http/2等协议强制要求,与本地cpu架构无关;错用littleendian会导致数值完全错误且无报错,如0x12345678误读为0x78563412。

网络字节序就是大端序,binary.BigEndian 是唯一安全、跨平台、协议兼容的选择,别用 binary.LittleEndian 去碰 TCP/IP、DNS 或任何标着 “network byte order” 的协议。
为什么必须用 binary.BigEndian 而不是本地 CPU 字节序
网络协议(TCP 头、UDP 校验和、HTTP/2 帧长度字段)明确要求大端序,和你跑在 x86 还是 ARM 上完全无关。binary.BigEndian 是纯字节操作,不依赖 CPU 架构——它把 0x12345678 固定写成 []byte{0x12, 0x34, 0x56, 0x78},错用 LittleEndian 就会变成 []byte{0x78, 0x56, 0x34, 0x12},数值直接翻错,且无 panic、无 warning,只默默返回错误值。
- 常见错误现象:
binary.Read不报错但解析出的uint32是几百万或负数(比如本该是 1024 却读成 134217728) - 校验失败:TCP 校验和字段错位、包长度字段溢出导致后续 payload 解析全乱
- 别试图用
unsafe或math.Float64bits手动翻字节——跨平台不可靠,Go 1.20+ 对未对齐访问更敏感,容易 panic
binary.BigEndian.Uint16 和 PutUint16 的典型用法与边界检查
这两个函数只操作前两个字节,传入切片长度不足会 panic,不是返回 error。所以必须确保底层数组至少有 2 字节可用。
Go语言(Golang)1.26.0版本提供 Go 官方 Windows amd64 MSI 安装包下载入口,版本号 1.26.0,可用于旧项目维护、兼容性测试和指定版本开发环境配置。
- 读取:
binary.BigEndian.Uint16(buf[off:])等价于 Node.js 的buf.readUInt16BE(off),但前提是len(buf) >= off + 2 - 写入:
binary.BigEndian.PutUint16(buf[off:], val)同样要求len(buf) >= off + 2,否则 runtime panic: "index out of range" - 不要复用同一段
[]byte作多次Put*而不检查偏移——比如PutUint16(buf, a); PutUint32(buf[2:], b),得确认len(buf) >= 6
用 binary.Write 写 struct 时最容易漏掉的三件事
binary.Write 看似方便,但 struct 字段顺序、类型宽度、导出性稍有偏差就会写错字节或 panic。
- 只处理导出字段(首字母大写),
flag uint16这种小写字段会被跳过,导致写入字节数变少 - 字段类型必须显式指定宽度:
int、uint不行,得用int32、uint16——因为不同平台下int可能是 4 或 8 字节 - 结构体不能含指针、slice、map、func;含
string会写入其 header(非内容),含[]byte同理;要传原始字节得用[N]byte数组
binary.Read 遇到 TCP 流式数据不全时怎么避免 io.ErrUnexpectedEOF
TCP 是流,binary.Read 一发现字节不够就立刻返回 io.ErrUnexpectedEOF,不会等、不会填零、也不会部分解析——这是设计使然,不是 bug。
- 别直接把
net.Conn.Read返回的n忽略,拿整个 buffer 交给binary.Read;必须先判断len(buf) >= expected_size - 固定头(如 6 字节 header)用
io.ReadFull(conn, headerBuf),它会阻塞直到读满或出错 - 变长 payload 先从 header 解出
Len,再make([]byte, Len),再io.ReadFull(conn, payload);别用bytes.Buffer单元测试——它永远返回 full read,掩盖真实 partial 场景
真正难的不是调用哪个函数,而是每次读写前都得心里默算字节偏移、长度约束和协议定义是否对齐;哪怕一个字段多 1 字节 padding,整包就废。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










