Todd

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            65 隨筆 :: 0 文章 :: 24 評論 :: 0 Trackbacks

          最近在項目開發過程中,需要在采用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,!@#$%^&*,見鬼去吧 -_-|||

               為什么要注意字節序的問題呢?你可能這么問。當然,如果你寫的程序只在單機環境下面運行,并且不和別人的程序打交道,那么你完全可以忽略字節序的存在。但是,如果你的程序要跟別人的程序產生交互呢?在這里我想說說兩種語言。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;
          }

          }

          posted on 2010-04-15 10:37 Todd 閱讀(1141) 評論(0)  編輯  收藏 所屬分類: java
          主站蜘蛛池模板: 睢宁县| 兰考县| 济宁市| 邵阳市| 两当县| 马山县| 香港| 逊克县| 舒兰市| 云林县| 偃师市| 通许县| 尉氏县| 望奎县| 永清县| 桃园市| 曲松县| 漯河市| 广饶县| 京山县| 界首市| 台安县| 南汇区| 教育| 德江县| 桂阳县| 简阳市| 宁明县| 友谊县| 赣榆县| 黄大仙区| 大理市| 沁阳市| 视频| 义马市| 连州市| 延边| 如东县| 宝山区| 漳浦县| 保康县|