- 浏览: 31702 次
- 性别:
- 来自: 上海
文章分类
最新评论
BIG-ENDIAN(大字节序、高字节序)
LITTLE-ENDIAN(小字节序、低字节序)
主机字节序
网络字节顺序
JAVA字节序
1.BIG-ENDIAN、LITTLE-ENDIAN跟多字节类型的数据有关的比如int,short,long型,而对单字节数据byte却没有影响。BIG-ENDIAN就是低位字节排放在内存的低端,高位字节排放在内存的高端。而LITTLE-ENDIAN正好相反。
比如 int a = 0x05060708
在BIG-ENDIAN的情况下存放为:
字节号 0 1 2 3
数据 05 06 07 08
在LITTLE-ENDIAN的情况下存放为:
字节号 0 1 2 3
数据 08 07 06 05
2.BIG-ENDIAN、LITTLE-ENDIAN、跟CPU有关的,每一种CPU不是BIG-ENDIAN就是LITTLE-ENDIAN、。IA架构的CPU中是Little-Endian,而PowerPC 、SPARC和Motorola处理器。这其实就是所谓的主机字节序。而网络字节序是指数据在网络上传输时是大头还是小头的,在Internet的网络字节序是BIG-ENDIAN。所谓的JAVA字节序指的是在JAVA虚拟机中多字节类型数据的存放顺序,JAVA字节序也是BIG-ENDIAN。
3.所以在用C/C++写通信程序时,在发送数据前务必用htonl和htons去把整型和短整型的数据进行从主机字节序到网络字节序的转换,而接收数据后对于整型和短整型数据则必须调用ntohl和ntohs实现从网络字节序到主机字节序的转换。如果通信的一方是JAVA程序、一方是C/C++程序时,则需要在C/C++一侧使用以上几个方法进行字节序的转换,而JAVA一侧,则不需要做任何处理,因为JAVA字节序与网络字节序都是BIG-ENDIAN,只要C/C++一侧能正确进行转换即可(发送前从主机序到网络序,接收时反变换)。如果通信的双方都是JAVA,则根本不用考虑字节序的问题了。
4.如果网络上全部是PowerPC,SPARC和Motorola CPU的主机那么不会出现任何问题,但由于实际存在大量的IA架构的CPU,所以经常出现数据传输错误。
5.文章开头所提出的问题,就是因为程序运行在X86架构的PC SERVER上,发送数据的一端用C实现的,接收一端是用JAVA实现的,而发送端在发送数据前未进行从主机字节序到网络字节序的转换,这样接收端接收到的是LITTLE-ENDIAN的数据,数据解释自然出错。
具体数据如下,实际发送的数据为23578
发送端发送数据: 1A 5C
接收端接收到数据后,按BIG-ENDIAN进行解释具体数据是多少?你们自己去计算并比较吧!
===============================================================================================
Big Endian and Little Endian
谈到字节序的问题,必然牵涉到两大CPU派系。那就是Motorola的PowerPC系列CPU和Intel的x86系列CPU。PowerPC系列采用big endian方式存储数据,而x86系列则采用little endian方式存储数据。那么究竟什么是big endian,什么又是little endian呢?
其实big endian是指低地址存放最高有效字节(MSB),而little endian则是低地址存放最低有效字节(LSB),即常说的低位在先,高位在后。
用文字说明可能比较抽象,下面用图像加以说明。比如数字0x12345678在两种不同字节序CPU中的存储顺序如下所示:
Big Endian
低地址 高地址
----------------------------------------->
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 12 | 34 | 56 | 78 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Little Endian
低地址 高地址
----------------------------------------->
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 78 | 56 | 34 | 12 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
从上面两图可以看出,采用big endian方式存储数据是符合我们人类的思维习惯的。而little endian,!@#$%^&*,见鬼去吧 -_-|||
为什么要注意字节序的问题呢?你可能这么问。当然,如果你写的程序只在单机环境下面运行,并且不和别人的程序打交道,那么你完全可以忽略字节序的存在。但是,如果你的程序要跟别人的程序产生交互呢?尤其是当你把你在微机上运算的结果运用到计算机群上去的话。在这里我想说说两种语言。C/C++语言编写的程序里数据存储顺序是跟编译平台所在的CPU相关的,而JAVA编写的程序则唯一采用big endian方式来存储数据。试想,如果你用C/C++语言在x86平台下编写的程序跟别人的JAVA程序互通时会产生什么结果?就拿上面的 0x12345678来说,你的程序传递给别人的一个数据,将指向0x12345678的指针传给了JAVA程序,由于JAVA采取big endian方式存储数据,很自然的它会将你的数据翻译为0x78563412。什么?竟然变成另外一个数字了?是的,就是这种后果。因此,在你的C程序传给JAVA程序之前有必要进行字节序的转换工作。
无独有偶,所有网络协议也都是采用big endian的方式来传输数据的。所以有时我们也会把big endian方式称之为网络字节序。当两台采用不同字节序的主机通信时,在发送数据之前都必须经过字节序的转换成为网络字节序后再进行传输。ANSI C中提供了四个转换字节序的宏。
========================================================================================================
/**
* 通信格式转换
*
* Java和一些windows编程语言如c、c++、delphi所写的网络程序进行通讯时,需要进行相应的转换
* 高、低字节之间的转换
* windows的字节序为低字节开头
* linux,unix的字节序为高字节开头
* java则无论平台变化,都是高字节开头
*/
public class FormatTransfer {
/**
* 将int转为低字节在前,高字节在后的byte数组
* @param n int
* @return byte[]
*/
public static byte[] toLH(int n) {
byte[] b = new byte[4];
b[0] = (byte) (n & 0xff);
b[1] = (byte) (n >> 8 & 0xff);
b[2] = (byte) (n >> 16 & 0xff);
b[3] = (byte) (n >> 24 & 0xff);
return b;
}
/**
* 将int转为高字节在前,低字节在后的byte数组
* @param n int
* @return byte[]
*/
public static byte[] toHH(int n) {
byte[] b = new byte[4];
b[3] = (byte) (n & 0xff);
b[2] = (byte) (n >> 8 & 0xff);
b[1] = (byte) (n >> 16 & 0xff);
b[0] = (byte) (n >> 24 & 0xff);
return b;
}
/**
* 将short转为低字节在前,高字节在后的byte数组
* @param n short
* @return byte[]
*/
public static byte[] toLH(short n) {
byte[] b = new byte[2];
b[0] = (byte) (n & 0xff);
b[1] = (byte) (n >> 8 & 0xff);
return b;
}
/**
* 将short转为高字节在前,低字节在后的byte数组
* @param n short
* @return byte[]
*/
public static byte[] toHH(short n) {
byte[] b = new byte[2];
b[1] = (byte) (n & 0xff);
b[0] = (byte) (n >> 8 & 0xff);
return b;
}
/**
* 将将int转为高字节在前,低字节在后的byte数组
public static byte[] toHH(int number) {
int temp = number;
byte[] b = new byte[4];
for (int i = b.length - 1; i > -1; i--) {
b = new Integer(temp & 0xff).byteValue();
temp = temp >> 8;
}
return b;
}
public static byte[] IntToByteArray(int i) {
byte[] abyte0 = new byte[4];
abyte0[3] = (byte) (0xff & i);
abyte0[2] = (byte) ((0xff00 & i) >> 8);
abyte0[1] = (byte) ((0xff0000 & i) >> 16);
abyte0[0] = (byte) ((0xff000000 & i) >> 24);
return abyte0;
}
*/
/**
* 将float转为低字节在前,高字节在后的byte数组
*/
public static byte[] toLH(float f) {
return toLH(Float.floatToRawIntBits(f));
}
/**
* 将float转为高字节在前,低字节在后的byte数组
*/
public static byte[] toHH(float f) {
return toHH(Float.floatToRawIntBits(f));
}
/**
* 将String转为byte数组
*/
public static byte[] stringToBytes(String s, int length) {
while (s.getBytes().length < length) {
s += " ";
}
return s.getBytes();
}
/**
* 将字节数组转换为String
* @param b byte[]
* @return String
*/
public static String bytesToString(byte[] b) {
StringBuffer result = new StringBuffer("");
int length = b.length;
for (int i=0; i<length; i++) {
result.append((char)(b & 0xff));
}
return result.toString();
}
/**
* 将字符串转换为byte数组
* @param s String
* @return byte[]
*/
public static byte[] stringToBytes(String s) {
return s.getBytes();
}
/**
* 将高字节数组转换为int
* @param b byte[]
* @return int
*/
public static int hBytesToInt(byte[] b) {
int s = 0;
for (int i = 0; i < 3; i++) {
if (b >= 0) {
s = s + b;
} else {
s = s + 256 + b;
}
s = s * 256;
}
if (b[3] >= 0) {
s = s + b[3];
} else {
s = s + 256 + b[3];
}
return s;
}
/**
* 将低字节数组转换为int
* @param b byte[]
* @return int
*/
public static int lBytesToInt(byte[] b) {
int s = 0;
for (int i = 0; i < 3; i++) {
if (b[3-i] >= 0) {
s = s + b[3-i];
} else {
s = s + 256 + b[3-i];
}
s = s * 256;
}
if (b[0] >= 0) {
s = s + b[0];
} else {
s = s + 256 + b[0];
}
return s;
}
/**
* 高字节数组到short的转换
* @param b byte[]
* @return short
*/
public static short hBytesToShort(byte[] b) {
int s = 0;
if (b[0] >= 0) {
s = s + b[0];
} else {
s = s + 256 + b[0];
}
s = s * 256;
if (b[1] >= 0) {
s = s + b[1];
} else {
s = s + 256 + b[1];
}
short result = (short)s;
return result;
}
/**
* 低字节数组到short的转换
* @param b byte[]
* @return short
*/
public static short lBytesToShort(byte[] b) {
int s = 0;
if (b[1] >= 0) {
s = s + b[1];
} else {
s = s + 256 + b[1];
}
s = s * 256;
if (b[0] >= 0) {
s = s + b[0];
} else {
s = s + 256 + b[0];
}
short result = (short)s;
return result;
}
/**
* 高字节数组转换为float
* @param b byte[]
* @return float
*/
public static float hBytesToFloat(byte[] b) {
int i = 0;
Float F = new Float(0.0);
i = ((((b[0]&0xff)<<8 | (b[1]&0xff))<<8) | (b[2]&0xff))<<8 | (b[3]&0xff);
return F.intBitsToFloat(i);
}
/**
* 低字节数组转换为float
* @param b byte[]
* @return float
*/
public static float lBytesToFloat(byte[] b) {
int i = 0;
Float F = new Float(0.0);
i = ((((b[3]&0xff)<<8 | (b[2]&0xff))<<8) | (b[1]&0xff))<<8 | (b[0]&0xff);
return F.intBitsToFloat(i);
}
/**
* 将byte数组中的元素倒序排列
*/
public static byte[] bytesReverseOrder(byte[] b) {
int length = b.length;
byte[] result = new byte[length];
for(int i=0; i<length; i++) {
result[length-i-1] = b;
}
return result;
}
/**
* 打印byte数组
*/
public static void printBytes(byte[] bb) {
int length = bb.length;
for (int i=0; i<length; i++) {
System.out.print(bb + " ");
}
System.out.println("");
}
public static void logBytes(byte[] bb) {
int length = bb.length;
String ut = "";
for (int i=0; i<length; i++) {
ut = out + bb + " ";
}
}
/**
* 将int类型的值转换为字节序颠倒过来对应的int值
* @param i int
* @return int
*/
public static int reverseInt(int i) {
int result = FormatTransfer.hBytesToInt(FormatTransfer.toLH(i));
return result;
}
/**
* 将short类型的值转换为字节序颠倒过来对应的short值
* @param s short
* @return short
*/
public static short reverseShort(short s) {
short result = FormatTransfer.hBytesToShort(FormatTransfer.toLH(s));
return result;
}
/**
* 将float类型的值转换为字节序颠倒过来对应的float值
* @param f float
* @return float
*/
public static float reverseFloat(float f) {
float result = FormatTransfer.hBytesToFloat(FormatTransfer.toLH(f));
return result;
}
}
发表评论
-
java spring 框架 mvc 开发,action配置
2011-09-08 10:10 897<?xml version="1.0" ... -
JAVA 的 AES 加密方式使用
2011-09-08 00:05 1314简单的AES加密,废话不多说,直接代码 ========== ... -
Java JPA 操作数据,事物控制不完整 clear(),merge()方法分析
2011-08-19 12:19 3215最近在使用框架 spring+jpa+cxf 部署一个服务,出 ... -
Invocation of init method failed; nested exception is javax.xml.ws.WebServiceEx
2011-08-04 10:50 4208在webservice项目中,出 ... -
Missing classpath entry D:\jboss-4.0.5.GA \server\default\lib\mail.jar
2011-07-26 12:38 2299尝试新版本Eclipse3.7 indigo 加载jboss4 ... -
System.getProperty以获取的值
2011-07-12 12:03 1050System.out.println("java_v ... -
Xstream 对象与xml 互转
2011-06-29 17:55 1515需要 jar : xtream.jar ... -
jsp jstl标签使用
2011-06-29 16:27 1122JSTL使用表达式来简化页面的代码,这对一些标准的方法,例如b ... -
List 分组
2011-06-29 16:26 840private Map<String, Map<S ... -
Eclipse不自动编译 手动project》Clean
2011-06-29 16:23 2676打开project->build automatical ... -
Context initialization failed
2011-06-29 16:17 3782错误描述:Context initialization fai ... -
打包jar文件,但是java项目中引用了jar文件
2011-06-20 18:27 844插件地址,在线安装 http://kurucz-grafika ... -
java 按行读取文件内容
2011-06-20 10:40 1111String readPath = ""; ... -
使用Common-fileUpload 上传文件 读取文件内容
2011-05-05 23:17 1427private String fileTmpPath = &q ... -
简易读取配置在xml中的内容
2011-05-05 10:22 747一般我们会把经常修改的内容写在xml中利于我们修改,维护信息 ...
相关推荐
Java 流在处理上分为字符流和字节流。字符流处理的单元为 2 个字节的 Unicode 字符,分别操作字符、字符数组或字符串,而字节流处理单元为 1 个字节,操作字节和字节数组。 Java 内用 Unicode 编码存储字符,字符流...
Java字符流和字节流
举例而言,有一个4字节的数据0x01020304,要存储在内存中或文件中编号0~3字节的位置,两种字节序的排列方式分别如下:Big Endian 低地址
主要介绍了计算一个Java对象占用字节数的方法,较为详细的分析了Java中各类对象所占用的字节数,需要的朋友可以参考下
Java实现字节流与图片的转化
java基本类型与字节流的转换工具类
JAVA 字符流与字节流
我测试了一个前端时间开发的一个网络通讯工具,其中用到了很多java15的特性,例如泛形,增强循环,静态引入等功能,以及jdk15独有的类文件,例如StringBuilder等。通过该工具进行转换,可以完美的运行在java14环境...
Java中的字节流.
JAVA字节码JAVA字节码
二进制杂谈 1、十进制、二进制、十六进制 2、计算机储存单位 3、进制转换 4、有符号编码 5、反码的设计原理 6、二进制的位运算 7、位操作符 8、内存与内存地址 9、字节序 10、Java解码 11、Java编码
Java字节流 .pdf 学习资料 复习资料 教学资源
java字节码反编译工具 JAD+FrontEnd
关于java字节码的开源介绍,可以参考来吧 关于java字节码的开源介绍,可以参考来吧
java字节码加密
Java SE程序 字节文件保存到磁盘DateInputStream类Java SE程序 字节文件保存到磁盘DateInputStream类Java SE程序 字节文件保存到磁盘DateInputStream类Java SE程序 字节文件保存到磁盘DateInputStream类Java SE程序 ...
用于设备通讯之类转化,可供大学,我也测试过OK,可以使用
面向Java锁机制的字节码自动重构框架
深入Java编程_Java的字节代码.pdf
java编译后的字节码编辑器。注意,不是反编译器,而是对class文件进行直接修改。 需要对虚拟机的指令有所了解,才可以正确使用。 直接边界16进制的class文件。