先交待一下業(yè)務(wù)應(yīng)用背景: 服務(wù)端:移動(dòng)交費(fèi)系統(tǒng):基于C語(yǔ)言的Unix系統(tǒng) 客戶端:增值服務(wù)系統(tǒng):基于Java的軟件系統(tǒng) 通迅協(xié)議:采用TCP/IP協(xié)議,使用TCP以異步方式接入 數(shù)據(jù)傳輸:基于Socket流的方式,傳輸?shù)氖蔷W(wǎng)絡(luò)字節(jié)序
Java Socket通訊實(shí)現(xiàn)方式這里不做過(guò)多的描述,網(wǎng)上到處可以搜索到,比較簡(jiǎn)單,這里要說(shuō)的是Java 與 C 進(jìn)行Socket通訊需注意的地方:
1、Java與C的各種數(shù)據(jù)類(lèi)型存儲(chǔ)的字節(jié)數(shù)是不同的:
Java與C的數(shù)據(jù)類(lèi)型的比較 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
所以在通訊前,需要進(jìn)行類(lèi)型轉(zhuǎn)換,對(duì)于C定義的unsign char為一個(gè)字節(jié)存儲(chǔ),對(duì)應(yīng)Java這邊用byte存儲(chǔ);對(duì)于C定義的int, long, float對(duì)應(yīng)Java用int存儲(chǔ),具體可以參考以上的表。
2、Socket通訊是按字節(jié)傳輸?shù)模?個(gè)bit位傳輸),而對(duì)于超過(guò)一個(gè)字節(jié)的類(lèi)型如short 為兩個(gè)字節(jié),就存在兩種傳輸入方式,一種是高字節(jié)在前傳輸;一種是高字節(jié)在后傳輸。即Little-Endian和Big-Endian。 Little-Endian和Big-Endian是表示計(jì)算機(jī)字節(jié)順序的兩種格式,所謂的字節(jié)順序指的是長(zhǎng)度跨越多個(gè)字節(jié)的數(shù)據(jù)的存放形式. 假設(shè)從地址0x00000000開(kāi)始的一個(gè)字中保存有數(shù)據(jù)0x1234abcd,那么在兩種不同的內(nèi)存順序的機(jī)器上從字節(jié)的角度去看的話分別表示為: 1)little endian:在內(nèi)存中的存放順序是0x00000000-0xcd,0x00000001-0xab,0x00000002-0x34,0x00000003-0x12 2)big endian:在內(nèi)存中的存放順序是0x00000000-0x12,0x00000001-0x34,0x00000002-0xab,0x00000003-0xcd 需要特別說(shuō)明的是,以上假設(shè)機(jī)器是每個(gè)內(nèi)存單元以8位即一個(gè)字節(jié)為單位的. 簡(jiǎn)單的說(shuō),ittle endian把低字節(jié)存放在內(nèi)存的低位;而big endian將低字節(jié)存放在內(nèi)存的高位. 現(xiàn)在主流的CPU,intel系列的是采用的little endian的格式存放數(shù)據(jù),而motorola系列的CPU采用的是big endian.
網(wǎng)絡(luò)協(xié)議都是Big-Endian的,Java編譯的都是Big-Endian的,C編譯的程序是與機(jī)器相關(guān)的,具體是否要進(jìn)行轉(zhuǎn)換是需要溝通的。假設(shè)這里需要轉(zhuǎn)換,以下提供short轉(zhuǎn)的換成字節(jié)數(shù)組的方式:
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; } 其它的類(lèi)型轉(zhuǎn)換類(lèi)似,無(wú)非是根據(jù)類(lèi)型在判斷用幾個(gè)字節(jié)進(jìn)行存儲(chǔ)而已。
3、由于Socket通訊是按字節(jié)進(jìn)行傳輸?shù)模贘ava中只有byte是一個(gè)字節(jié),故可以將其它類(lèi)型都轉(zhuǎn)換成byte數(shù)組來(lái)存儲(chǔ),如:short用兩位的字節(jié)數(shù)組存儲(chǔ),需轉(zhuǎn)換了換以上方法進(jìn)行,而int用四位的字節(jié)數(shù)組來(lái)存儲(chǔ),對(duì)String類(lèi)型,直接用String.getBytes()來(lái)得到它的字節(jié)數(shù)組。
4、Java的byte與C語(yǔ)言的unsign char雖然都是一個(gè)字節(jié)存儲(chǔ),但具體的表示內(nèi)容是不同的,C的無(wú)符號(hào)char是取值的范圍0--255,而Java中byte取值的范圍是-128—127,故在實(shí)現(xiàn)C語(yǔ)言的字符串時(shí)(C是用char[]來(lái)表示字符串的),Java這邊需要進(jìn)行轉(zhuǎn)換來(lái)模仿C語(yǔ)的unsign char,具體實(shí)現(xiàn)函數(shù)如下: // 將有符號(hào)的char轉(zhuǎn)換成無(wú)符號(hào)的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; } 這里的關(guān)鍵點(diǎn)是當(dāng)signChar[i] < 0時(shí),即加上256,將其轉(zhuǎn)換到0--255中來(lái)。
通過(guò)以上四個(gè)方面的注意,基本上就可以實(shí)現(xiàn)Java與C進(jìn)行Socket通訊了。
|