先交待一下業務應用背景:
服務端:移動交費系統:基於C語言的Unix系統
客戶端:增值服務系統:基於Java的軟件系統
通迅協議:采用TCP/IP協議,使用TCP以異步方式接入
數據傳輸:基於Socket流的方式,傳輸的是網絡字節序
Java Socket通訊實現方式這裡不做過多的描述,網上到處可以搜索到,比較簡單,這裡要說的是Java 與 C 進行Socket通訊需注意的地方:
1、Java與C的各種數據類型存儲的字節數是不同的:
Java與C的數據類型的比較
Type Java C
short 2-Byte 2-Byte
int 4-Byte 4-Byte
long 8-Byte 4-Byte
float 4-Byte 4-Byte
double 8-Byte 8-Byte
boolean 1-bit N/A
byte 1-Byte N/A
char 2-Byte 1-Byte
所以在通訊前,需要進行類型轉換,對於C定義的unsign char為一個字節存儲,對應Java這邊用byte存儲;對於C定義的int, long, float對應Java用int存儲,具體可以參考以上的表。
2、Socket通訊是按字節傳輸的(即8個bit位傳輸),而對於超過一個字節的類型如short 為兩個字節,就存在兩種傳輸入方式,一種是高字節在前傳輸;一種是高字節在後傳輸。即Little-Endian和Big-Endian。
Little-Endian和Big-Endian是表示計算機字節順序的兩種格式,所謂的字節順序指的是長度跨越多個字節的數據的存放形式.
假設從地址0x00000000開始的一個字中保存有數據0x1234abcd,那麼在兩種不同的內存順序的機器上從字節的角度去看的話分別表示為:
1)little endian:在內存中的存放順序是0x00000000-0xcd,0x00000001-0xab,0x00000002-0x34,0x00000003-0x12
2)big endian:在內存中的存放順序是0x00000000-0x12,0x00000001-0x34,0x00000002-0xab,0x00000003-0xcd
需要特別說明的是,以上假設機器是每個內存單元以8位即一個字節為單位的.
簡單的說,ittle endian把低字節存放在內存的低位;而big endian將低字節存放在內存的高位.
現在主流的CPU,intel系列的是采用的little endian的格式存放數據,而motorola系列的CPU采用的是big endian.
網絡協議都是Big-Endian的,Java編譯的都是Big-Endian的,C編譯的程序是與機器相關的,具體是否要進行轉換是需要溝通的。假設這裡需要轉換,以下提供short轉的換成字節數組的方式:
public static byte[] ShorttoByteArray(short n) {
byte[] b = new byte[2];
b[1] = (byte) (n & 0xff);
b[0] = (byte) (n >> 8 & 0xff);
return b;
}
public static byte[] toLH(short n) {
byte[] b = new byte[2];
b[0] = (byte) (n & 0xff);
b[1] = (byte) (n >> 8 & 0xff);
return b;
}
其它的類型轉換類似,無非是根據類型在判斷用幾個字節進行存儲而已。
3、由於Socket通訊是按字節進行傳輸的,而在Java中只有byte是一個字節,故可以將其它類型都轉換成byte數組來存儲,如:short用兩位的字節數組存儲,需轉換了換以上方法進行,而int用四位的字節數組來存儲,對String類型,直接用String.getBytes()來得到它的字節數組。
4、Java的byte與C語言的unsign char雖然都是一個字節存儲,但具體的表示內容是不同的,C的無符號char是取值的范圍0--255,而Java中byte取值的范圍是-128—127,故在實現C語言的字符串時(C是用char[]來表示字符串的),Java這邊需要進行轉換來模仿C語的unsign char,具體實現函數如下:
// 將有符號的char轉換成無符號的char
public static char[] ToUnsignedChar(char[] signChar) {
for (int i = 0; i < signChar.length; i++) {
int x = ((byte) signChar[i]) >= 0 ? signChar[i] : ((byte) signChar[i]) + 256;
signChar[i] = (char) x;
}
return signChar;
}
這裡的關鍵點是當signChar[i] < 0時,即加上256,將其轉換到0--255中來。
通過以上四個方面的注意,基本上就可以實現Java與C進行Socket通訊了。