二进制协议

基于文本类型的协议(比如 JSON)和二进制协议都是字节通信,他们不同点在于他们使用哪种类型的字节和如何组织这些字节。

文本协议只适用于 ASCII 或 Unicode 编码可打印的字符通信。例如 “26” 使用 “2” 和 “6” 的 utf 编码的字符串表示,这种方式方便我们读,但对于计算机效率较低。

在二进制协议中,同样数字 “26” ,二进制(0001 1010),可使用一个字节 0x1A 十六进制表示,减少了一半的存储空间,且原始的字节格式能够被计算机直接识别而不需解析。当一个数字足够大的时候,性能优势就会明显体现。

计算机字节序和网络字节序

字节序

就是多字节数据类型 (int, float 等)在内存中的存储顺序。可分为大端序和小端序:

  • 大端序:低地址端存放高位字节;
  • 小端序:与之相反,低地址端存放低位字节。

例如

在计算机内部,小端序被广泛应用于现代性 CPU 内部存储数据;而在其他场景譬如网络传输和文件存储使用大端序

使用小端序时不移动字节就能改变 number 占内存的大小而不需内存地址起始位。比如我想把四字节的 int32 类型的整型转变为八字节的 int64 整型,只需在小端序末端加零即可。

44 33 22 11
44 33 22 11 00 00 00 00

上述扩展或缩小整型变量操作在编译器层面非常有用,但在网络协议层非也。

在网络协议层操作二进制数字时约定使用大端序,大端序是网络字节传输采用的方式。因为大端序最高有效字节排在首位(低地址端存放高位字节),能够按照字典排序,所以我们能够比较二进制编码后数字的每个字节。

例如:

Go的binary库

Go语言的encoding/binary包实现了简单的数字(固定长度的数字类型或者只包含定长值的结构体或数组)与字节系列的转换以及变长值的编解码。

序列化,将数据转换成byte字节流,order指定字节序

func Write(w io.Writer, order ByteOrder, data interface{}) error

反序列化,将字节流转换成原始数据

func Read(r io.Reader, order ByteOrder, data interface{}) error

order: binary.BigEndian(大端模式):内存的低地址存放着数据高位 binary.LittleEndian(小端模式):内存的低地址存放着数据地位

参考资料

Go语言的序列化与反序列化(binary)

字节序与go binary库