Java與C/C++網路通訊時的資料轉換

來源:互聯網
上載者:User

標籤:java   socket   網路通訊   c++   大小端   

最近做了一款Android應用,需要和PC端通過socket傳遞資料。PC端是用C++開發的,為了方便傳輸,在發送之前都將資料轉化為位元組數組。本以為可以萬事大吉,可是過程還是會有一些問題。下面是我遇到的幾個問題以及解決方案,這裡做一個簡單的記錄,也希望大家遇到後能夠快速解決,同時歡迎各位補充指正~

Java Socket的接收與發送

首先我們會建立一個socket串連,然後從中擷取InputStream和OutputStream。在接收的時候我是用一個DataInputStream對Socket的InputStream進行封裝,便於後面接收不同大小的資料類型。在發送時先通過DataOutputStream()對OutputStream進行封裝,然後將不同的資料類型寫入,最後用ByteArrayOutputStream封裝轉化成位元組流,通過已經建立好的Socket通道發送。這樣以來會有以下兩個問題。

問題一:大小端問題

PC端裝置使用的是x86平台, 資料為小端格式。而jvm虛擬機器採用的大端格式,當你用Java讀取一個位元組,如:調用dataInputStream.read()的時候,可以正常的讀出一個位元組。但是如果要讀出多位元組的資料類型,如:dataInputStream.readInt()的時候,就會出現大小端的資料錯誤。小端格式會把低位元組的資料存放區在低地址儲存空間,而大端格式會把低位元組的資料存放區在高地址空間。這樣以來,資料的高地位就正好顛倒了。

解決方案

這個問題的解決方案也比較容易,通過對錯誤資料高地位進行蝶形交換可以得到結果。對於大小端格式轉換可以先做一個基於short的轉換,然後對Int資料高低位分別調用short的轉換即可,代碼如下:

    /**     * 大小端蝶形交換     *      * @param data     *            待交換的short資料     * @return 轉換後的short數     */    private static short swapShortToLittleEndian(short data)    {        short ret = (short) ((data << 8) | (data >> 8) & 0x00FF);        ret = (short) (ret & 0xFFFF);        return ret;    }

然後對於int資料可以分別對高低16位進行以上轉換:

    /**     * 大小端蝶形交換     *      * @param data     *            待交換的int資料     * @return 轉換後的int數     */private static void swapIntToLittleEndian(int data)    {        int ret = swapShortToLittleEndian((short) ((data >> 16) & 0xFFFF))                | (swapShortToLittleEndian((short) data) << 16);        return ret;    }

經過以上兩種函數可以將16位元組、32位元組的資料轉為小端格式,對於64位的可以採用同樣的原理。
PS:可能有朋友會對上面頻繁的和0xFFFF/0xFF作與運算有些疑惑,這裡也是要說的第二個問題,這個與運算是必須的,下面來說說原因

問題二:Java隱式類型轉換

在Java中,對byte 的 + - * / >> >>> << & | ^ (加,減,乘,除,右移,左移,無符號右移,位與,位或,位異或)操作,均會是首先將byte轉化為int, 再行運算。然後,這一過程可能導致多種問題。

解決方案

大家知道在Java中為了方便資料的處理,只存在有符號數。即用最高位來表示符號,其餘位表示實際的資料。在上面大小端轉換中,我們需要首先將低8位元據移到高8位,同時將高8位元據移到低8位。在左移的過程當中,右邊毫無疑問是自動補0,那麼直接進行移位的結果會是我們想要的結果。但是如果是右移,對於正數而言(最高位是0),也能得到正確的結果;然而如果是負數(最高位是1),此時右移的時候高位是會自動補1,當然這個可以通過運算子“>>>”來解決,但是這裡還有另一個問題:當對byte移位時,系統會將其隱式轉為int資料,如果是負數,那麼補齊的高位元據則全為1
如果在右移之後不和0xFF做位與,那麼之後和高位元據位或拼接的時候高位會直接全為1,這也就是為什麼會頻繁做位與操作的原因。
綜上:
1. 用Java接收C++無符號資料的時候,一定要注意大小端的轉換。
2. 另外遇到移位操作,需要注意在右移之後必須將高位清零來消除錯誤。

以上是個人遇到的問題及自己的解決方案,如有更多方案,歡迎補充!

Java與C/C++網路通訊時的資料轉換

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.