本本人從事Android開發(fā)工作,最近由于工作需要,需要與C++語言服務器進行TCP交互。在java中Socket編程已經為我們封裝了很多好用的Api,今天我們討論的是和C++交互過程中的一些心得。首先要明確幾個概念 :
什么是內存對齊為什么要內存對齊-內存對齊:
內存對齊,或者說字節(jié)對齊,是一個數據類型所能存放的內存地址的屬性(Alignment is a PRoperty of a memory address)。 這個屬性是一個無符號整數,并且這個整數必須是2的N次方(1、2、4、8、……、1024、……)。 當我們說,一個數據類型的內存對齊為8時,意思就是指這個數據類型所定義出來的所有變量,其內存地址都是8的倍數。
當一個基本數據類型(fundamental types)的對齊屬性,和這個數據類型的大小相等時,這種對齊方式稱作自然對齊(naturally aligned)。 比如,一個4字節(jié)大小的int型數據,默認情況下它的字節(jié)對齊也是4。 -為什么要內存對齊:
這是因為,并不是每一個硬件平臺都能夠隨便訪問任意位置的內存的。我個人的理解可能在不同的平臺上面內存的分配情況是不一樣的。這個也是導致java中沒有結構體這個數據結構的原因。 我們都知道,在結構體內部可能有多個基本類型,那么子阿布同平臺他所占的內存大小也是不一樣的的使用。那么問題來了,java中如何實現(xiàn)C或C++中的結構體類型。
-Javolution 這是一個第三方資源庫。 [ Javolution ]
javolution的使用:
1 javolution支持maven方式引入
<dependency> <groupId>org.javolution</groupId> <artifactId>javolution-core-java</artifactId> <version>6.0.0</version> </dependency>2 可以下載相應的Jar加入到你的工程中。(注意:我開始下載的是5.X版本,有些問題。下載6.x就好了)。
開始使用Javolution: 在java中若要定義結構體形式的數據結構。你的類首先應該繼承Javolution的Struct類。而且java中的基本類型也不能直接使用。要使用Struct類中的基本類型,如下:
public final Signed32 version = new Signed32(); public final Signed32 eMainType = new Signed32(); public final Bool hasSubtype = new Bool(); public final Signed32 nLen = new Signed32(); public final UTF8String HeadEnding = new UTF8String(2); public final Signed32 eSubType = new Signed32();值得注意的是:在你自己定義的“結構體”中,ByteOrder方法返回的小端對齊的。
另外在附加兩個工具方法。分別是Struct轉成byte[]和byte[]轉成Struct:
/** * 把類型轉化成byte數組 * @param struct 實體類型 * @return */ public static byte[] GetBytesFromStruct( javolution.io.Struct struct) { int sz = struct.size(); ByteBuffer bb = struct.getByteBuffer(); if( bb == null)return null; byte[] buffer = new byte[sz]; bb.position(0); // 設置位置 bb.get(buffer);// System.out.println(bb); return buffer; }/** * 把byte數組轉換成類型 * * @param struct 實體類型 * @param bytes 原始數據流 * @param offset 開始位置 * @param length 取長度 * @return */ public static Struct GetStructFromByte(Struct struct, byte[] bytes,int offset,int length) { ByteBuffer bb = ByteBuffer.wrap(bytes, offset, length); bb.position(0); bb.order(ByteOrder.LITTLE_ENDIAN); struct.setByteBuffer(bb, 0); return struct; } 值得注意的是: 1 關于如何為結構體賦值或是獲取其中某個屬性的值可以通過Struct.XXX.set()和 Struct.XXX.get()方法實現(xiàn)。 2 在你自己定義的結構體中,每個參數的順序要按照協(xié)議約定的順序,否則返回的結構將不是你期待的結果。 3 獲取你自己定義的結構的內存大小使用的Struct.Size()方法。網上有對這種方式的問題做出了總結,目前本人還沒有遇到: 一 對齊方式改變了:結構體在遇到64位的數據類型的時候,就自動把前面的數據按8字節(jié)對齊了,這樣子的話coin數據本應該是由數據流的第12字節(jié)的位置開始解析變成了第16個字節(jié)開始解析,后面的數據就必然會跟著移位 二 在C中char content[0]content數據存儲的是可變數據的開始地址,在c的結構體里是不占用大小的,所以這個結構體的大小應該為2.在java里就定義不出來的
詳細問題與解決方式的請參考。 [ Javolution的坑 ]
以上就是在這次工作中的一點心得,另外網上還有一種實現(xiàn)方式是通過JNI來實現(xiàn)的。個人還沒有嘗試。
|
新聞熱點
疑難解答