原文:http://lihaoquan.me/2016/11/5/golang-byteorder.html

这个人的博客写的不错,品质也比较高。 我应该也要有这种精神,这种态度。深入到计算机的世界中去。也是一种快乐。

使用Go开发一个简单反向代理服务 这篇文章也要研究一下。很好
---------------------------------------------------------------------------------------------
go语言的字节序

go

最近在看nsq的源码时候,发现它处理message的时候,都会采用字节序进行数据包的处理,于是我觉得有必要深入了解下TCP协议中 字节序的知识

字节序(Byte Order)

我们一般把字节(byte)看作是数据的最小单位。当然,其实一个字节中还包含8个bit (bit = binary digit)。 在一个32位的CPU中“字长”为32个bit,也就是4个byte。在这样的CPU中,总是以4字节对齐的方式来读取或写入内存, 那么同样这4个字节的数据是以什么顺序保存在内存中的呢?我们下面详细探讨一下。

字节序包括:大端序和小端序,为什么要这么麻烦还要分门别类呢?举个例子,255用二进制表达就是1111 1111,再加1就是1 0000 0000,多了一个1出来,显然我们需要再用额外的一个字节来存放这个1,但是这个1要存放在第一个字节还是第二个字节呢?这时候因为人们选择的不同,就出现了大端序和小端序的差异。

而所谓大字节序(big endian),便是指其“最高有效位(most significant byte)”落在低地址上的存储方式。例如像地址a写入0x0A0B0C0D之后,在内存中的数据便是:

而对于小字节序(little endian)来说就正好相反了,它把“最低有效位(least significant byte)”放在低地址上。例如:

对于我们常用的CPU架构,如Intel,AMD的CPU使用的都是小字节序,而例如Mac OS以前所使用的Power PC使用的便是大字节序(不过现在Mac OS也使用Intel的CPU了)。

Go 处理字节序

Go中处理大小端序的代码位于 encoding/binary ,包中的全局变量BigEndian用于操作大端序数据,LittleEndian用于操作小端序数据,这两个变量所对应的数据类型都实行了ByteOrder接口:

type ByteOrder interface {
Uint16([]byte) uint16
Uint32([]byte) uint32
Uint64([]byte) uint64
PutUint16([]byte, uint16)
PutUint32([]byte, uint32)
PutUint64([]byte, uint64)
String() string
}

其中,前三个方法用于读取数据,后三个方法用于写入数据。

大家可能会注意到,上面的方法操作的都是无符号整型,如果我们要操作有符号整型的时候怎么办呢?很简单,强制转换就可以了,比如这样:

func PutInt32(b []byte, v int32) {
binary.BigEndian.PutUint32(b, uint32(v))
}

为了深入了解它们,我们先写一个程序观察下go处理大端序和小端序的方式:

package main

import (
"encoding/binary"
"fmt"
"unsafe"
) const INT_SIZE int = int(unsafe.Sizeof(0)) //判断我们系统中的字节序类型
func systemEdian() {
var i int = 0x1
bs := (*[INT_SIZE]byte)(unsafe.Pointer(&i))
if bs[0] == 0 {
fmt.Println("system edian is little endian")
} else {
fmt.Println("system edian is big endian")
}
} func testBigEndian() { // 0000 0000 0000 0000 0000 0001 1111 1111
var testInt int32 = 256
fmt.Printf("%d use big endian: \n", testInt)
var testBytes []byte = make([]byte, 4)
binary.BigEndian.PutUint32(testBytes, uint32(testInt))
fmt.Println("int32 to bytes:", testBytes) convInt := binary.BigEndian.Uint32(testBytes)
fmt.Printf("bytes to int32: %d\n\n", convInt)
} func testLittleEndian() { // 0000 0000 0000 0000 0000 0001 1111 1111
var testInt int32 = 256
fmt.Printf("%d use little endian: \n", testInt)
var testBytes []byte = make([]byte, 4)
binary.LittleEndian.PutUint32(testBytes, uint32(testInt))
fmt.Println("int32 to bytes:", testBytes) convInt := binary.LittleEndian.Uint32(testBytes)
fmt.Printf("bytes to int32: %d\n\n", convInt)
} func main() {
systemEdian()
fmt.Println("")
testBigEndian()
testLittleEndian()
}

执行的结果:

system edian is big endian

256 use big endian:
int32 to bytes: [0 0 1 0]
bytes to int32: 256 256 use little endian:
int32 to bytes: [0 1 0 0]
bytes to int32: 256

总结

为了程序的兼容,我们在开发跨服务器的TCP服务时,每次发送和接受数据都要进行转换,这样做的目的是保证代码在任何计算机上执行时都能达到预期的效果。

【转】go语言的字节序的更多相关文章

  1. C语言字节对齐问题详解(对齐、字节序、网络序等)

    首先说明一下,本文是转载自: http://www.cnblogs.com/clover-toeic/p/3853132.html 博客园用的少,不知道怎么发布转载文章,只能暂时这样了. 引言 考虑下 ...

  2. C语言中的位域、字节序、比特序、大小端

    转:http://www.360doc.com/content/13/0624/10/496343_295125641.shtml 1.比特序 / 位序 /  bit numbering / bit  ...

  3. 用C语言,如何判断主机是 大端还是小端(字节序)

    所谓大端就是指高位值在内存中放低位地址,所谓小端是指低位值在内存中放低位地址.比如 0x12345678 在大端机上是 12345678,在小端机上是 78564312,而一个主机是大端还是小端要看C ...

  4. 09.C语言:预处理(宏定义)、字节序、地址对齐

    一.预处理 预处理 gcc -E Hello.c -o hello.i 编译 gcc -S hello.i -o hello.s 汇编 gcc -c hello.s -o hello.o 链接 gcc ...

  5. c语言getipaddrtable获得ip地址与sendArp获得mac地址以及一些字节序问题记录

    https://docs.microsoft.com/zh-cn/windows/win32/api/iphlpapi/nf-iphlpapi-getipaddrtable msdn,有很多c的源码还 ...

  6. PHP: 深入pack/unpack 字节序

    http://my.oschina.net/goal/blog/195749?p=1 目录[-] 写在前面的话 什么是字节序 MSB和LSB 大端序 小端序 网络字节序 主机字节序 总结 pack/u ...

  7. 【MINA】字节序知识

    字节序,分为高位在前和低位在前,说白了就是先从低操作还是从高位操作 java和网络的字节序是一致的,都是高位在前,这意味着java端序列化和反序列化时不用关心字节序的问题, 那问题是,那讨论字节序有什 ...

  8. TODO:字节序的一些理解

    TODO:字节序的一些理解 本文是小编对字节序的片面理解,希望对你有帮助哈. 字节序,即字节在电脑中存放时的序列与输入(输出)时的序列是先到的在前还是后到的在前. 1.Little endian:将低 ...

  9. 刨根究底字符编码之十一——UTF-8编码方式与字节序标记

    UTF-8编码方式与字节序标记 一.UTF-8编码方式 1. 接下来将分别介绍Unicode字符集的三种编码方式:UTF-8.UTF-16.UTF-32.这里先介绍应用最为广泛的UTF-8. 为满足基 ...

随机推荐

  1. 从零开始,学习web前端之HTML5开发

    什么是HTML5 HTML5是HTML最新的修订版本,2014年10月由万维网联盟(W3C)完成标准制定.是下一代 HTML 标准. 为什么要学习HTML5 HTML5定义了一系列新元素,如新语义标签 ...

  2. 转:Apache+Fastcgi+Django

    07年作者就贴出的文章了,可见多么古老的运行方式还在用. 转:http://www.cnblogs.com/RChen/archive/2007/03/23/django_fcgi.html 首先要安 ...

  3. 字符串匹配&Rabin-Karp算法讲解

    问题描述: Rabin-Karp的预处理时间是O(m),匹配时间O( ( n - m + 1 ) m )既然与朴素算法的匹配时间一样,而且还多了一些预处理时间,那为什么我们还要学习这个算法呢?虽然Ra ...

  4. 【Maven】maven的常用命令以及搭建maven私人仓库

    一.maven环境搭建 1. 二.maven常用命令 1.创建一个新的项目: mvn archetype:create -DgroupId=com.puyangsky.test -DartifactI ...

  5. 文件还原工具Foremost

    文件还原工具Foremost   在数字取证中,通过对设备备份,可以获取磁盘镜像文件.通过分析镜像文件,可以获取磁盘存在的数据.但是很多重要数据往往已被删除.这个时候,就需要还原这些文件.Kali L ...

  6. Electron:将前端应用打包成桌面应用

    首先戳我下载安装对应版本的node.js. 安装完成后,打开命令行输入node -v以及npm -v查看对应版本.能够正常显示说明安装成功. 写一个最简单的hello world的nodejs应用.n ...

  7. Redux-react connect 源码自己重写

    import Counter from '../components/Counter'; import { increment, decrement, incrementIfOdd, incremen ...

  8. 雅礼集训DAY 6 T1 xmasdag

    感谢gryz的mly大好人再次给我提供了题目和数据. 和昨晚那个题几乎一样,都是x^n最后转化成第二类斯特林数*阶乘*Σ(和路径长度有关的组合数),而因为组合数是可以利用Pascal公式实现O(1)递 ...

  9. bzoj 3140: [Hnoi2013]消毒

    3140: [Hnoi2013]消毒 Description 最近在生物实验室工作的小T遇到了大麻烦. 由于实验室最近升级的缘故,他的分格实验皿是一个长方体,其尺寸为a*b*c,a.b.c 均为正整数 ...

  10. git远程仓库创建及权限管理(一)单个项目

    最近接手公司git权限管理,既然负责此事个人觉得应该深入学习下,不仅为当前工作也为进一步发展.网上查找了一番,找到了完整的教程,所以这里不再一步一步描述,具体链接已给出,本文只对操作过程中遇到的问题的 ...