网络字节序与主机字节序 高低位

最近在项目开发过程中,需要在采用JAVA作为语言的服务器与采用C++作为语言的服务器间进行通信,这就涉及到这两种语言间数据类型的转换以及网络字节序与主机字节序的区别。该文主要说说网络字节序和主机字节序的区别以及Little
endian与Big endian的概念。其实编程的事就比较简单了
   我也懒得写了,直接引用了我觉得写的挺好的两篇文章

什么是Big
Endian和Little Endian?

来源:http://blog.ednchina.com/qinyonglyz/194674/message.aspx

1.故事的起源

“endian”这个词出自《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开,由此曾发生过六次叛乱,其中一个皇帝送了命,另一个丢了王位。

我们一般将endian翻译成“字节序”,将big endian和little endian称作“大尾”和“小尾”。

2.什么是Big Endian和Little Endian?

在设计计算机系统的时候,有两种处理内存中数据的方法。一种叫为little-endian,存放在内存中最低位的数值是来自数据的最右边部分(也就是数据的最低位部分)。比如一个16进制数字0x12345678,在内存存放的方式如下:














0111,1000

0101,0110

0011,0100

0001,0010

地址

100

101

102

103

另一种称为big-endian,正好相反,存放在内存中最低位的数值是来自数据的最左边边部分(也就是数据的最高为部分)。比如一个16进制数字0x12345678,在内存存放的方式如下:














0001,0010

0011,0100

0101,0110

0111,1000

地址

100

101

102

103

比如某些文件需要在不同平台处理,或者通过Socket通信。这方面我们可以借助ntohl(), ntohs(), htonl(),
and htons()函数进行格式转换。

3.如何判断系统是Big Endian还是Little Endian?

在/usr/include/中(包括子目录)查找字符串BYTE_ORDER(或_BYTE_ORDER,
__BYTE_ORDER),确定其值。这个值一般在endian.h或machine/endian.h文件中可以找到,有时在feature.h中,不同的操作系统可能有所不同。一般来说,Little
Endian系统BYTE_ORDER(或_BYTE_ORDER,__BYTE_ORDER)为1234,Big
Endian系统为4321。大部分用户的操作系统(如windows, FreeBsd,Linux)是Little Endian的。少部分,如MAC OS
,是Big Endian 的。本质上说,Little Endian还是Big Endian与操作系统和芯片类型都有关系。

======================================================================

ext3 文件系统在硬盘分区上的数据是按照 Intel 的 Little-endian 格式存放的,如果是在 PC 以外的平台上开发 ext3
相关的程序,要特别注意这一点。

谈到字节序的问题,必然牵涉到两大
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,[email protected]#$%^&*,见鬼去吧
-_-|||

    
为什么要注意字节序的问题呢?你可能这么问。当然,如果你写的程序只在单机环境下面运行,并且不和别人的程序打交道,那么你完全可以忽略字节序的存在。但是,如果你的程序要跟别人的程序产生交互呢?在这里我想说说两种语言。C/C++语言编写的程序里数据存储顺序是跟编译平台所在的CPU相关的,而
JAVA编写的程序则唯一采用big
endian方式来存储数据。试想,如果你用C/C++语言在x86平台下编写的程序跟别人的JAVA程序互通时会产生什么结果?就拿上面的
0x12345678来说,你的程序传递给别人的一个数据,将指向0x12345678的指针传给了JAVA程序,由于JAVA采取big
endian方式存储数据,很自然的它会将你的数据翻译为0x78563412。什么?竟然变成另外一个数字了?是的,就是这种后果。因此,在你的C程序传给JAVA程序之前有必要进行字节序的转换工作

    
无独有偶,所有网络协议也都是采用big endian的方式来传输数据的。所以有时我们也会把big
endian方式称之为网络字节序。当两台采用不同字节序的主机通信时,在发送数据之前都必须经过字节序的转换成为网络字节序后再进行传输。

网络字节序与主机字节序

来源:http://www.cnblogs.com/jacktu/archive/2008/11/24/1339789.html
不同的CPU有不同的字节序类型
这些字节序是指整数在内存中保存的顺序 这个叫做主机序
最常见的有两种
1. Little endian:将低序字节存储在起始地址
2. Big
endian:将高序字节存储在起始地址

LE
little-endian
最符合人的思维的字节序
地址低位存储值的低位
地址高位存储值的高位
怎么讲是最符合人的思维的字节序,是因为从人的第一观感来说
低位值小,就应该放在内存地址小的地方,也即内存地址低位
反之,高位值就应该放在内存地址大的地方,也即内存地址高位

BE
big-endian
最直观的字节序
地址低位存储值的高位
地址高位存储值的低位
为什么说直观,不要考虑对应关系
只需要把内存地址从左到右按照由低到高的顺序写出
把值按照通常的高位到低位的顺序写出
两者对照,一个字节一个字节的填充进去

例子:在内存中双字0x01020304(DWORD)的存储方式

内存地址
4000
4001 4002 4003
LE 04 03 02 01
BE 01 02 03
04

例子:如果我们将0x1234abcd写入到以0x0000开始的内存中,则结果为
      big-endian  little-endian
0x0000  0x12      0xcd
0x0001  0x23      0xab
0x0002  0xab      0x34
0x0003  0xcd      0x12
x86系列CPU都是little-endian的字节序.

网络字节顺序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节顺序采用big
endian排序方式。

为了进行转换 bsd socket提供了转换的函数 有下面四个
htons 把unsigned
short类型从主机序转换到网络序
htonl 把unsigned long类型从主机序转换到网络序
ntohs 把unsigned
short类型从网络序转换到主机序
ntohl 把unsigned long类型从网络序转换到主机序

在使用little
endian的系统中 这些函数会把字节序进行转换
在使用big endian类型的系统中 这些函数会定义成空宏

同样 在网络程序开发时
或是跨平台开发时 也应该注意保证只用一种字节序 不然两方的解释不一样就会产生bug.

注:
1、网络与主机字节转换函数:htons
ntohs htonl ntohl (s 就是short l是long h是host
n是network)
2、不同的CPU上运行不同的操作系统,字节序也是不同的,参见下表。
处理器    操作系统    字节排序
Alpha    全部    Little
endian
HP-PA    NT    Little
endian
HP-PA    UNIX    Big
endian
Intelx86    全部    Little
endian
<-----x86系统是小端字节序系统
Motorola680x()    全部    Big
endian
MIPS    NT    Little
endian
MIPS    UNIX    Big
endian
PowerPC    NT    Little
endian
PowerPC    非NT    Big
endian  <-----PPC系统是大端字节序系统
RS/6000    UNIX    Big
endian
SPARC    UNIX    Big
endian
IXP1200 ARM核心    全部    Little
endian
=============================================
字节序转换类:

/**
*
通信格式转换
*
* 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;
}

}

时间: 2024-12-15 22:39:22

网络字节序与主机字节序 高低位的相关文章

c# 主机和网络字节序的转换 关于网络字节序和主机字节序的转换

最近使用C#进行网络开发,需要处理ISO8583报文,由于其中有些域是数值型的,于是在传输的时候涉及到了字节序的转换. 字节顺序是指占内存多于一个字节类型的数据在内存中的存放顺序,通常有两种字节顺序,根据他们所处的位置我们分别称为主机节序和网络字节序. 通常我们认为网络字节序为标准顺序,封包的时候,将主机字节序转换为网络字节序,拆包的时候要将网络字节序转换为主机字节序. 原以为还要自己写函数,其实网络库已经提供了. 主机到网络:short/int/long IPAddress.HostToNet

网络字节序与主机字节序

最近在项目开发过程中,需要在采用JAVA作为语言的服务器与采用C++作为语言的服务器间进行通信,这就涉及到这两种语言间数据类型的转换以及网络字节序与主机字节序的区别.该文主要说说网络字节序和主机字节序的区别以及Little endian与Big endian的概念.其实编程的事就比较简单了   我也懒得写了,直接引用了我觉得写的挺好的两篇文章: 什么是Big Endian和Little Endian? 来源:http://blog.ednchina.com/qinyonglyz/194674/m

网络字节序和主机字节序

1.大端.小端字节序 考虑一个16位整数,它由2个字节组成.内存中存储这两个字节有两种方法:一种是将低序字节存储在起始地址,这称为小端(little-endian)字节序:另一种方法是将高序字节存储在起始地址,这称为大端(big-endian)字节序.如下所示: 术语“大端”和“小端”表示多个字节值的哪一端(小端或大端)存储在该值的起始地址. 遗憾的是,这两种字节序之间没有标准可循,两种格式都有系统使用.比如,Inter x86.ARM核采用的是小端模式,Power PC.MIPS UNIX和H

大端模式与小端模式、网络字节顺序与主机字节顺序

大端模式与小端模式 一.概念及详解 在各种体系的计算机中通常采用的字节存储机制主要有两种: big-endian和little-endian,即大端模式和小端模式. 先回顾两个关键词,MSB和LSB: MSB:Most Significant Bit  ------- 最高有效位     LSB:Least Significant Bit ------- 最低有效位 大端模式(big-edian) big-endian:MSB存放在最低端的地址上. 举例,双字节数0x1234以big-endia

大端模式和小端模式 网络字节顺序与主机字节顺序

在 各种计算机体系结构中,对于字节.字等的存储机制有所不同,因而引发了计算机 通信领 域中一个很重要的问题,即通信双方交流的信息单元(比特.字节.字.双字等等)应该以什么样的顺序进行传送.如果不达成一致的规则,通信双方将无法进行正 确的编/译码从而导致通信失败.目前在各种体系的计算机中通常采用的字节存储机制主要有两种:Big-Endian和Little-Endian,下面先从字节序说起.一.什么是字节序字节序,顾名思义字节的顺序,再多说两句就是大于一个字节类型的数据在内存中的存放顺序(一个字节的

网络字节序与主机字节序的转换

在对IP地址结构体SOCKADDR_IN赋值的时候,经常会用到下列的函数htonl,htons,inet_addr,与之相对应的函数是ntohl,ntohs,inet_ntoa.查看这些函数的解析,会发现这些函数其实是与主机字节序和网络字节序之间转换有关.就是什么网络字节序,什么是主机字节序呢?下面我写出他们之间的转换: 用IP地址127.0.0.1为例: 第一步   127     .         0         .         0         .        1      

Python网络编程——主机字节序和网络字节序之间的相互转换

If you ever need to write a low-level network application, it may be necessary to handle the low-level data transmission over the wire between two machines. This operation requires some sort of conversion of data from the native host operating system

python通过ntohl和htonl等函数实现主机字节序和网络字节序相互转换

Python的socket库提供了将数据在网络字节序和主机字节序之间相互转换的函数.有什么作用呢? 在编写低层网络应用时,或许需要处理通过电缆在两台设备之间传送的低层数据.在这种操作中,需要把主机操作系统发出的数据转换成网络格式,或者做逆向转换,因为这两种数据的表示方式不一样. 技术点解析: 1.定义convert_integer()函数,注意函数格式(以后都会提醒这个,要养成习惯) 2.socket库中的类函数 ntohl() 把网络字节序转换成了长整形主机字节序 htonl() 把长整形主机

网络与主机字节转换函数:htons ntohs htonl ntohl

网络与主机字节转换函数:htons ntohs htonl ntohl 网络字节序: 网络字节顺序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型.操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释.网络字节顺序采用big endian(大端)排序方式. 注:网络字节序转化为主机字节序时,一定要注意是否需要转换.网络字节序是确定的. 大端与小端 大端:低地址存高位 —— 网络字节序/主机字节序 小端:高地址存低位 —— 主机字节序 网络字节序一定是大端的(网络上传输