通訊中的字節網絡順序和字節主機順序

http://blog.csdn.net/sergeycao/archive/2009/02/24/3933149.aspx

 

 

C/C++寫網絡程序的時候,往往會遇到字節的網絡順序和主機順序的問題。

 
其實數據的順序是由cpu決定的,與操作系統無關。 
Intel   x86結構下,short型數0x1234表示爲34   12,int型數0x12345678表示爲78   56   34   12  
IBM   power PC結構下,short型數0x1234表示爲12   34,int型數0x12345678表示爲12   34   56   78
  
由於這個原因不同的機器之間無法通信,所以要轉換成一種約定的數序,也就是網絡字節順序,其實就是如同power   pc那樣的順序 
PC開發中有ntohlhtonl函數可以用來進行網絡字節和主機字節的轉換,但是Symbian開發中沒有這兩個函數,那就要自己寫接口來進行轉換了。
下面是兩個進行轉換的接口:
 
//主機順序轉換成網絡順序網絡順序轉換成主機順序
inline   unsigned   long   HTONL(unsigned   long   h)  
    {  
      return   (h>>24)+((h>>16)<<8)+((h>>8)<<16)+(h<<24);  
    }
 
//主機順序轉換成網絡順序網絡順序轉換成主機順序 
    inline   unsigned   short   HTONS(unsigned   short   h)  
    {  
      return   (h>>8)+(h<<8);  
    }
 
 
這些問題在Java做爲Server端,Symbian做爲Client端時表現的更爲明顯,因爲Java中的通訊傳輸的都是網絡字節。到了Symbian端要轉換成主機字節。
比如你要發送一個結構  
  struct test{  
    short   a;  
    int      b;
    long   c;  
    float   d;   
    double  f;  
  };  
  test st;  
  char *p   =   (char*)&st;//
看看p中的字節順序(就是發送的字節順序)  
   
  java
端你相應寫些函數進行轉換就行了。  
 
舉一個例子:  
      //
c對應的ntohl函數  
      public   static   long   ntohl(long   in){  
          long   out   =   0;  
          out     =   (in&0xff)<<24;    
          out   |=   (in&0xff00)<<8;  
          out   |=   (in&0xff0000)>>8;  
          out   |=   (in&0xff000000)>>24;  
          return   out;  
      }
 
下面再轉幾篇不錯的文章:
原文地址:http://blog.csdn.net/kingfish/archive/2005/03/29/333635.aspx

近幾天看到csdn上問c/c++和java通信的問題比較多,特別是c特有的數據結構(如struct)。

特地根據網友的一個問題舉個例子,希望對初學者有所幫助。

原問題見:http://community.csdn.net/Expert/topic/3886/3886989.xml?temp=.3527033

這類問題通常是爲了利用原有Server或者Server不能做修改(通常是c/c++)造成。

比如Server端只接收一個結構Employee,定義如下:

struct UserInfo {
               char UserName[20];
               int UserId;
        };
       struct Employee {
               UserInfo user;
               float salary;
      };
當然也可以定義爲

struct Employee {
              char name[20];
              int    id;
            float salary;
};

java client 測試源碼(爲說明問題,假設struct字節對齊,sizeof(Employee)=28)

import java.net.*;

/*
          * 與C語言通信(java做Client,c/c++做Server,傳送一個結構)
          * @author kingfish
          * @version 1.0
       */
class Employee {
  private byte[] buf = new byte[28];  //爲說明問題,定死大小,事件中可以靈活處理

  /*
           * 將int轉爲低字節在前,高字節在後的byte數組
         */
  private 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;
  }

  /*
           * 將float轉爲低字節在前,高字節在後的byte數組
         */
  private static byte[] toLH(float f) {
    return toLH(Float.floatToRawIntBits(f));
  }

  /*
           * 構造並轉換
         */
  public Employee(String name, int id, float salary) {
    byte[] temp = name.getBytes();
    System.arraycopy(temp, 0, buf, 0, temp.length);

    temp = toLH(id);
    System.arraycopy(temp, 0, buf, 20, temp.length);

    temp = toLH(salary);
    System.arraycopy(temp, 0, buf, 24, temp.length);
  }

  /**
   * 返回要發送的數組
   */
  public byte[] getBuf() {
    return buf;
  }

  /**
   * 發送測試
   */
  public static void main(String[] args) {
    try {
      Socket sock = new Socket("127.0.0.1", 8888);
      sock.getOutputStream().write(new Employee("kingfish", 123456789, 8888.99f).
                                   getBuf());
      sock.close();
    }
    catch (Exception e) {
      e.printStackTrace();
    }

} //end

當然,也可以利用writeInt,writeFloat方法發送,但字節順序需要改爲低在前。
這個問題稍後在討論。

第一部分請見http://blog.csdn.net/kingfish/archive/2005/03/29/333635.aspx

本部分提出另外一種做法, 供參考。


import java.net.*;
import java.io.*;

/**
 * 與C語言通信(java做Client,c/c++做Server,傳送一個結構)
 * @author kingfish
 * @version 1.0
 */
public class Employee2 {
  private String name;
  private int id;
  private float salary;

  /**
   * 將int轉爲低字節在前,高字節在後的int
   */
  private static int toLH(int in) {
    int out = 0;
    out = (in & 0xff) << 24;
    out |= (in & 0xff00) << 8;
    out |= (in & 0xff0000) >> 8;
    out |= (in & 0xff000000) >> 24;
    return out;
  }

  /**
   * 將float轉爲低字節在前,高字節在後的int
   */
  private static int toLH(float f) {
    return toLH(Float.floatToRawIntBits(f));
  }

  /**
   * 構造並轉換
   */
  public Employee2(String name, int id, float salary) {
    this.name = name;
    this.id = id;
    this.salary = salary;
  }

  /**
   * 取得名字,定長byte數組
   */
  public byte[] getName() {
    byte[] b = new byte[20];
    System.arraycopy(name.getBytes(), 0, b, 0, name.getBytes().length);
    return b;
  }

  /**
   * 取得編號(低字節在前)
   */
  public int getId() {
    return toLH(id);
  }

  /**
   * 取得工資(低字節在前)
   */
  public int getSalary() {
    return toLH(salary);
  }

  /**
   * 發送測試
   */
  public static void main(String[] args) {
    try {
      Employee2 p = new Employee2("kingfish", 123456789, 8888.99f);

      Socket sock = new Socket("127.0.0.1", 8888);
      DataOutputStream dos = new DataOutputStream(sock.getOutputStream());
      dos.write(p.getName());
      dos.writeInt(p.getId());
      dos.writeInt(p.getSalary());

      sock.close();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }
} //end

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章