原文: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. 《The art of software testing》的一个例子

    这几天一直在看一本书,<The art of software testing>,里面有一个例子挺有感触地,写出来和大家分享一下: [问题] 从输入对话框中读取三个整数值,这三个整数值代表 ...

  2. 前端读者 | 前端构建工具Gulp

    @羯瑞 整理 前言 前端工具现在层出不穷,网上搜下一大片,就看你怎么去使用了,基于项目看用什么样的构建工具.有的工具提供的功能还是非常强大的. FIS.百度团队的产品.现在百度的多个产品中使用.面向前 ...

  3. gulp-基本功能总汇

    研究了三天的gulp,今天做一个结束吧. 本次包含的功能有: html压缩 图片压缩 css压缩 js检测 js压缩 文件合并 文件更名 提示信息 编译less 创建服务器-浏览器实时刷新 因为我安装 ...

  4. Djangp2.x版本报错找不到模版目录下的文件

    1.报错内容:django.template.exceptions.TemplateDoesNotExist: index.html 2.解决办法,在settings.py文件中,找到TEMPLATE ...

  5. ImportError: No module named etree.ElementTree

    ImportError: No module named etree.ElementTree 排查N久,才发现是因为文件名是xml.py的缘故,文件名一定不要用关键词.....

  6. centos7 mariaDB安装

    参考:http://www.linuxidc.com/Linux/2016-03/128880.htm

  7. 【转载】RecyclerView使用全解析

    崇拜下鸿洋大神,原文地址:http://blog.csdn.net/lmj623565791/article/details/45059587 概述 RecyclerView出现已经有一段时间了,相信 ...

  8. phpstorm中Xdebug的使用

    目 录 1.Xdebug简介 2.Xdebug的安装.操作   2.1环境搭建 2.2配置php.ini 2.3配置PhpStorm 2.4配置PHP Debug 2.5进行调试 1.Xdebug简介 ...

  9. 如何通过 Redis 实现分布式锁

    分布式锁需要解决的问题: 互斥性:任意时刻只能有一个客户端获取锁 安全性:锁只能被持有该锁的客户端删除 死锁:获取锁的客户端因为意外宕机未能释放锁,其他客户端再也无法获取到该锁导致死锁 容错:宕机后客 ...

  10. ZOJ 3324 Machine

    线段树,延迟标记. 记录一下每个节点代表的区间的最小值,以及左右端点是否为最小值,记录区间被下压几次作为延迟标记,再记录一下这个区间中有多少个最小值的连通块. $n$最大有$1$亿,可以开动态线段树避 ...