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,

[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方式稱之為網路位元組序
。當兩臺採用不同位元組序的主機通訊時,在傳送資料之前都必須經過位元組序的轉換成為網路位元組序後再進行傳輸。ANSI C中提供了四個轉換位元組序的巨集。

 


 

[html]  view plain  copy
  1. /**  
  2. * 通訊格式轉換  
  3. *  
  4. * Java和一些windows程式語言如c、c++、delphi所寫的網路程式進行通訊時,需要進行相應的轉換  
  5. * 高、低位元組之間的轉換  
  6. * windows的位元組序為低位元組開頭  
  7. * linux,unix的位元組序為高位元組開頭  
  8. * java則無論平臺變化,都是高位元組開頭  
  9.   */   
  10.   
  11. public class FormatTransfer {  
  12. /**  
  13.   * 將int轉為低位元組在前,高位元組在後的byte陣列  
  14.   * @param n int  
  15.   * @return byte[]  
  16.   */  
  17. public static byte[] toLH(int n) {  
  18.   byte[] b = new byte[4];  
  19.   b[0] = (byte) (n & 0xff);  
  20.   b[1] = (byte) (n >> 8 & 0xff);  
  21.   b[2] = (byte) (n >> 16 & 0xff);  
  22.   b[3] = (byte) (n >> 24 & 0xff);  
  23.   return b;  
  24. }   
  25.   
  26. /**  
  27.   * 將int轉為高位元組在前,低位元組在後的byte陣列  
  28.   * @param n int  
  29.   * @return byte[]  
  30.   */  
  31. public static byte[] toHH(int n) {  
  32.   byte[] b = new byte[4];  
  33.   b[3] = (byte) (n & 0xff);  
  34.   b[2] = (byte) (n >> 8 & 0xff);  
  35.   b[1] = (byte) (n >> 16 & 0xff);  
  36.   b[0] = (byte) (n >> 24 & 0xff);  
  37.   return b;  
  38. }   
  39.   
  40. /**  
  41.   * 將short轉為低位元組在前,高位元組在後的byte陣列  
  42.   * @param n short  
  43.   * @return byte[]  
  44.   */  
  45. public static byte[] toLH(short n) {  
  46.   byte[] b = new byte[2];  
  47.   b[0] = (byte) (n & 0xff);  
  48.   b[1] = (byte) (n >> 8 & 0xff);  
  49.   return b;  
  50. }   
  51.   
  52. /**  
  53.   * 將short轉為高位元組在前,低位元組在後的byte陣列  
  54.   * @param n short  
  55.   * @return byte[]  
  56.   */  
  57. public static byte[] toHH(short n) {  
  58.   byte[] b = new byte[2];  
  59.   b[1] = (byte) (n & 0xff);  
  60.   b[0] = (byte) (n >> 8 & 0xff);  
  61.   return b;  
  62. }   
  63.   
  64.   
  65.   
  66. /**  
  67.   * 將將int轉為高位元組在前,低位元組在後的byte陣列   
  68.   
  69. public static byte[] toHH(int number) {  
  70.   int temp = number;  
  71.   byte[] b = new byte[4];  
  72.   for (int i = b.length - 1; i > -1; i--) {  
  73.     b = new Integer(temp & 0xff).byteValue();  
  74.     temp = temp >> 8;  
  75.   }  
  76.   return b;  
  77. }   
  78.   
  79. public static byte[] IntToByteArray(int i) {  
  80.     byte[] abyte0 = new byte[4];  
  81.     abyte0[3] = (byte) (0xff & i);  
  82.     abyte0[2] = (byte) ((0xff00 & i) >> 8);  
  83.     abyte0[1] = (byte) ((0xff0000 & i) >> 16);  
  84.     abyte0[0] = (byte) ((0xff000000 & i) >> 24);  
  85.     return abyte0;  
  86. }   
  87.   
  88.   
  89. */   
  90.   
  91. /**  
  92.   * 將float轉為低位元組在前,高位元組在後的byte陣列  
  93.   */  
  94. public static byte[] toLH(float f) {  
  95.   return toLH(Float.floatToRawIntBits(f));  
  96. }   
  97.   
  98. /**  
  99.   * 將float轉為高位元組在前,低位元組在後的byte陣列  
  100.   */  
  101. public static byte[] toHH(float f) {  
  102.   return toHH(Float.floatToRawIntBits(f));  
  103. }   
  104.   
  105. /**  
  106.   * 將String轉為byte陣列  
  107.   */  
  108. public static byte[] stringToBytes(String s, int length) {  
  109.   while (s.getBytes().length < length) {  
  110.     s += " ";  
  111.   }  
  112.   return s.getBytes();  
  113. }   
  114.   
  115.   
  116. /**  
  117.   * 將位元組陣列轉換為String  
  118.   * @param b byte[]  
  119.   * @return String  
  120.   */  
  121. public static String bytesToString(byte[] b) {  
  122.   StringBuffer result = new StringBuffer("");  
  123.   int length = b.length;  
  124.   for (int i=0; i<length; i++) {  
  125.     result.append((char)(b & 0xff));  
  126.   }  
  127.   return result.toString();  
  128. }   
  129.   
  130. /**  
  131.   * 將字串轉換為byte陣列  
  132.   * @param s String  
  133.   * @return byte[]  
  134.   */  
  135. public static byte[] stringToBytes(String s) {  
  136.   return s.getBytes();  
  137. }   
  138.   
  139. /**  
  140.   * 將高位元組陣列轉換為int  
  141.   * @param b byte[]  
  142.   * @return int  
  143.   */  
  144. public static int hBytesToInt(byte[] b) {  
  145.   int s = 0;  
  146.   for (int i = 0; i < 

    相關推薦

    Java位元組(不同語言網路資料傳輸位元組序列轉換)

    BIG-ENDIAN(大位元組序、高位元組序) LITTLE-ENDIAN(小位元組序、低位元組序) 主機位元組序 網路位元組順序 JAVA位元組序 1.BIG-ENDIAN、LITTLE-ENDIAN跟多位元組型別的資料有關的比如

    Go語言其他資料與字串型別的轉換

    1 概述 Go語言是強型別語言,因此總會需要將字串轉成需要的型別。比如整型和字串轉換,字串和布林型的轉換等。本文就介紹如何完成這些轉換,以下是Go語言關於字串轉換的整理說明,主要是與切片型別的轉換,和 strconv 包的使用。 2 與切片的轉換 切片型別可以

    網路資料傳輸作業系統幹了什麼?

    ## 前言 最近在整理網路抓包分析相關的資料,同時又在閱讀《網路是怎樣連線的》。上一篇從網路協議層對裝置連網的過程和傳送資料的過程進行了探討。本篇討論的是TCP協議的資料收發的過程。 > 在討論本篇文章時,假設讀者對TCP協議有一定了解。 ## 建立Socket 由於TCP協議是需要建立連線的,

    Json資料傳輸LinkedTreeMap無法轉換到自己定義的型別

    如果傳輸的Json串為以下格式 {"code":0","contain":"kkkk","data":[{"id":1,"useraccount":"1",''question":"1","reply":"1"}]} 可建立一個通用類Message<T>,用於

    Java語言資料型別

    1.Java語言中的資料型別 為什麼要使用資料型別呢,因為我們要編寫程式,要編寫程式就要建立變數,而建立變數就需要資料型別。 建立變數時使用資料型別就可以指定,自己建立的變數在程式執行時所佔用的記憶體空間大小。 2.變數 任何一個程式中都有變數存在。 變數就是程式執行過程中隨時可能會發生變

    C語言各種資料型別所佔的位元組和取值範圍

    問題:C語言資料型別取值範圍,是根據什麼定義這個範圍取值? 首先,在計算機中所有資料都是用一個一個的二進位制位(0或1)儲存的,單位稱為:位(bit);然後,每8位二進位制數(比如01010001)代表一個位元組(byte)大小,即1位元組=8位;再然後,C語言每個資料型別

    java8基本資料型別佔用位元組空間

    基本資料型別 所佔用空間大小 byte b; 1位元組 short s; 2位元組 int i; 4位元組 long l; 8位元組 char c; 2位元組(C語言中是1位元組) flo

    網路程式設計】資料傳輸位元組

    前言 可能小組的同學很早就聽說過大小端,但是似乎這個順序並沒有什麼卵用。。(我就是這麼想的)不過在學習網路程式設計中,突然對這個問題有了新的認識,趕緊總結下,不然以後肯定踩坑。。。 本文假定讀者已經明白了大小端的區別,並且對於網路程式設計、TCP/IP有一定

    java資料儲存,位元組轉換,位操作

    1. java中資料儲存是按照位元組儲存的,一個位元組是8位,也就是java中的byte資料型別,java中byte表示的是有符號數,第八位(從右至左)表示的是符號位,一個位元組表示的範圍是2^8,也就是256個數,表示的範圍是:-128到127,因為第八位始終是符號位,所

    【轉載】筆記:無os的LwIP在TCP server歷程網路資料傳送,串口出現tcp_write及tcp_receive錯誤。

      2016年09月07日 22:13:58 新野-新野 閱讀數:6180 標籤: LWIP 更多 個人分類: 轉載筆記 做一個,串列埠收到資料然後通過tcp主動傳送出去的東西,但是目前遇到以下問題,當tcp初始化後連

    C語言資料

    基本型別 1.整型 指不帶小數的數字,也是最簡單最常用的 2.字元型 char 一般用來儲存當個字元 例如 char s1='a'; 3.浮點型 浮點資料是指代小數的數字 變數及賦值 變數定義的一般形式為:資料型別 變數名; 多個型別相同的變數: 資料型別 變數名,變數名,變數名..

    Java向word文件填充資料

    前言: 對於中大型OA系統來說,線上開啟word文件已經是一個常用需求。既然有線上操作word文件的需求,那就不可避免要有開啟文件時動態填充資料的需求。這篇文章就讓小編來介紹一箇中間件技術-pageoffice。 pageoffice對於word的功能做到了80%以上的封裝,而且api比較簡單容

    伺服器開發網路資料分析與故障排查經驗漫談

    寫在前面的話 “聽見學生時代愛聽的歌,加上太累,回家路上一下子想了好多,腳步慢了,眼眶溼了,不是感傷,而是生活呀,需要這麼多力量。過去那些跌跌撞撞忙碌的日子,怎麼說呢,多少有點像在逃避吧,聽起來不像是真的。” 以上這段話訴說了我的經歷,我也曾迷惘和無助過。也有很多朋友找

    python語言資料型別之元組

    資料型別 元組       tuple 元組:不可變型別 用途:元組就是一個不可變的列表,當需要存不改動的值時可用元組 定義方式:在()內用逗號分隔開多個任意型別的元素 t=(1,2.2,'aa',('b','c

    python語言資料型別之列表

    資料型別及內建方法 列表:     list    可變型別,有序 用途:用來記錄多個值(同屬性)   定義方式:在[  ]內用逗號分隔開多個任意型別的值 l=['a','b','c'] #l=li

    python語言資料型別之字典

    資料型別 字典型別dict 用途:記錄多個值,列表是索引對應值,而字典是key對應值,其中key對value有描述性 定義方式:在{ }用逗號分隔開多個元素,每個元素都是key:value形式,其中key是不可變型別,通常是字串型別,而value是任意型別。 型別轉換:

    python語言資料型別之集合

    資料型別 集合型別    set 用途:1.關係運算        2.去重 定義方式:在{}內用逗號分隔開多個元素,但元素的特點是 1.集合內元素必須是不可變型別

    java獲取配置檔案.properties資料

    方法太多,只寫一種比較簡單的。 檔案test1.properties內容 test1 = 123; test2=321 Properties prop = new Properties(); prop.load(new FileInputStre

    R語言資料結構

    R語言中的資料結構 文字中對R語言中的資料結構進行總結,以說明和舉例的方式展現出來! 主要包含:向量,陣列,列表,資料框,因子,矩陣,和一些常用函式。 注:以下程式碼均可直接執行! 1、向量 向量,用於儲存數值型,字元型,邏輯型資料的一維陣列 同一向量中無法混雜不同模式的資料

    c語言資料型別

    c語言中的資料型別 "資料型別": { "基本資料型別":{ //%d 以整數型輸出 "整型":{ //int 4位元組 -