`
arron.huang
  • 浏览: 32391 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Java 网络 网络字节序 字节序

    博客分类:
  • Java
 
阅读更多

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网络字节序转换1

    Java 网络字节序转换是编程过程中一个重要的概念,尤其在跨平台通信和处理二进制数据时。字节序是指多字节数据(如整数或浮点数)在内存或文件中存储的顺序。主要有两种字节序:Big-Endian(大端字节序)和 Little-...

    java-16进制4字节转Float

    Java中的默认字节序是网络字节序,也就是大端字节序。 2. **解析过程**:将16进制字符串转换为浮点数,通常涉及以下步骤: - 将16进制字符串转换为字节数组,每个字节对应一个16进制字符。 - 根据字节序调整字节...

    Java字符流与字节流区别

    Java 流在处理上分为字符流和字节流。字符流处理的单元为 2 个字节的 Unicode 字符,分别操作字符、字符数组或字符串,而字节流处理单元为 1 个字节,操作字节和字节数组。 Java 内用 Unicode 编码存储字符,字符流...

    Java实现字节流与图片的转化

    在Java编程中,字节流(Byte Stream)是处理数据的基本方式,特别是在处理二进制数据,如图片、音频或视频文件时。本教程将详细讲解如何使用Java实现字节流来转换和处理图片。 首先,我们需要理解字节流的概念。在...

    计算一个Java对象占用字节数的方法

    在Java编程语言中,了解一个对象占用的内存字节数对于优化内存使用和理解程序性能至关重要。本篇文章将深入探讨如何计算Java对象占用的内存字节数,以及影响这一数值的因素。 首先,Java对象在堆内存中由四个部分...

    Java字节流 .pdf

    Java字节流 Java字节流是一种用于处理字节数据的流处理机制,在Java中,字节流不包含边界数据的连续流,字节流是由字节组成的,Java里字符由两个字节组成。字节流是最基本的,它是按字节来处理二进制数据。 字节流...

    c++,java,php,c# 的网络字节流读写文件

    Java默认使用网络字节序,即大端模式。对于字节序转换,Java提供了`java.nio.ByteOrder`类,可以方便地在大端和小端之间切换。 PHP是另一种常用的Web开发语言,其文件操作主要通过`fopen`、`fwrite`和`fread`等函数...

    Java字符流和字节流

    ### Java字符流和字节流详解 #### 一、引言 在Java中,I/O流主要用于处理输入输出操作,包括文件读写等。根据处理数据类型的不同,Java I/O流主要分为字节流和字符流两大类。字节流处理的是8位的字节数据,而字符流...

    Java字节码转换工具—Retrotranslator

    Java字节码转换工具Retrotranslator是一个用于解决软件兼容性问题的实用工具,尤其是在Java版本升级带来的不兼容性上。随着Java技术的不断迭代,新版本的特性常常不能在旧版本的JDK环境下运行,而Retrotranslator的...

    java基本类型与字节流的转换工具类

    java基本类型与字节流的转换工具类

    Java中的字节流.

    ### Java中的字节流 #### 一、字节流简介 在Java中,字节流是一种处理二进制数据的基本方式。它通过一系列类来实现数据的读取和写入功能,这些类主要继承自`InputStream`和`OutputStream`两个抽象类。字节流非常...

    进制转换-编码的设计原理-位运算-内存与内存地址-字节序-java解码编码字节流

    二进制杂谈 1、十进制、二进制、十六进制 2、计算机储存单位 3、进制转换 4、有符号编码 5、反码的设计原理 6、二进制的位运算 7、位操作符 8、内存与内存地址 9、字节序 10、Java解码 11、Java编码

    ByteIO_java_字节流_

    在Java编程语言中,字节流(Byte Stream)是I/O操作的基础,它处理的是单个字节的数据。...通过学习和理解这段代码,开发者可以深入理解Java字节流的工作原理,提升在处理二进制数据和网络通信时的能力。

    JAVA 字符流与字节流

    在Java编程语言中,输入/输出(I/O)操作是处理数据流的关键部分,而字符流与字节流则是实现这些操作的两种基本方式。理解它们的区别和应用场景对于任何Java开发者来说都是至关重要的。 ### 字节流 字节流是最基本...

    JAVA作业三字节数组转化.docx

    需要注意的是,Java的标准字节序是大端字节序,但是这并不意味着所有的硬件平台都遵循这个标准。因此,在进行字节序转换时,尤其是在跨平台的环境中,我们需要特别注意字节序的问题,以确保数据的一致性和正确性。 ...

    面向Java锁机制的字节码自动重构框架.zip

    本文将深入探讨Java锁机制,并基于提供的"面向Java锁机制的字节码自动重构框架"来讨论其背后的原理和应用。 在Java中,锁主要分为内置锁(也称为监视器锁)和显式锁。内置锁是通过synchronized关键字实现的,它提供...

    Java开发-字节跳动(今日头条、抖音)面试真题.pdf.zip

    【Java开发-字节跳动面试真题解析】 在Java开发领域,字节跳动(包括今日头条和抖音)作为互联网巨头,其面试题库一直是广大求职者关注的焦点。这份"Java开发-字节跳动(今日头条、抖音)面试真题.pdf.zip"压缩包...

    JAVA字节码JAVA字节码.doc

    Java 字节码编程 Java 字节码是 Java 程序的中间表示形式,它可以被 Java 虚拟机(JVM)解释执行。了解 Java 字节码可以帮助开发者更好地理解 Java 程序的执行机制,提高程序的执行效率和排除错误。 一、Java 类...

    Java IO字符流和字节流

    ### Java IO字符流和字节流详解 #### 一、引言 在Java编程中,输入输出(简称IO)操作是十分重要的一个方面。通过IO操作,我们可以读取文件、网络数据、用户输入等,也可以将数据写入到文件、网络、控制台等。Java...

Global site tag (gtag.js) - Google Analytics