Android使用自定義TCP協(xié)議訪問(wèn)網(wǎng)絡(luò)(以二進(jìn)制流的方式)

由于服務(wù)器是自己搭建,直接使用TCP的Socket進(jìn)行訪問(wèn),并且傳輸?shù)氖亲远x格式數(shù)據(jù)幀,只提供主機(jī)地址和端口號(hào),并沒(méi)有請(qǐng)求的url,所以請(qǐng)求服務(wù)器不能使用現(xiàn)在的OKHttp等訪問(wèn)網(wǎng)絡(luò)的框架。

協(xié)議規(guī)范

協(xié)議頭+協(xié)議內(nèi)容

協(xié)議頭

MAGIC+LENGHT
MAGIC:魔數(shù), 固定為”0x8EEEEEEE”(自定義的十六進(jìn)制), unsigned int型, 4個(gè)字節(jié)
LENGTH:協(xié)議內(nèi)容的長(zhǎng)度, unsigned int型, 4字節(jié)

協(xié)議內(nèi)容

格式為json字符串

需要注意大小端的區(qū)別

java.nio.ByteOrder.LITTLE_ENDIAN:將低序字節(jié)存儲(chǔ)在起始地址(低位編址)
java.nio.ByteOrder.BIG_ENDIAN:將高序字節(jié)存儲(chǔ)在起始地址(高位編址)
x86系列CPU都是little-endian的字節(jié)序。

簡(jiǎn)單的封裝代碼如下

/**
 * Created by lexwu on 2017/1/23.
 * Socket訪問(wèn)網(wǎng)絡(luò)封裝
 */

public class HttpUtil {
    private static final String HOST = "10.100.0.100";//主機(jī)地址
    private static final int PORT = 9000;//端口號(hào)

    //TCP向服務(wù)端發(fā)送數(shù)據(jù)
    public static void requestServer(String json, CallListener callListener) {

        byte[] bytes1 = hexStringToByteArray("8EEEEEEE");//將自定義的16進(jìn)制魔數(shù)轉(zhuǎn)變?yōu)槎M(jìn)制的流
        byte[] bytes2 = intToBytes(json.length(), ByteOrder.BIG_ENDIAN);//將協(xié)議頭的LENGHT轉(zhuǎn)變?yōu)槎M(jìn)制的byte,第二個(gè)參數(shù)是大端
        byte[] byte3 = json.getBytes();  //將json數(shù)據(jù)轉(zhuǎn)換為二進(jìn)制的流
        byte[] bys = addBytes(bytes1, bytes2);//合并byte數(shù)組
        final byte[] bytes = addBytes(bys, byte3);//將3個(gè)byte數(shù)組合并為一個(gè)

        Socket socket = null;
        OutputStream output = null;
        InputStream input = null;
        StringBuffer sb = null;
        try {
            socket = new Socket(HOST, PORT);
            //--------向服務(wù)端的寫(xiě)入信息-------------
            output = socket.getOutputStream();
            output.write(bytes);// 把msg信息寫(xiě)入輸出流中
            //--------接收服務(wù)端的返回信息-------------
            socket.shutdownOutput(); // 一定要加上這句,否則收不到來(lái)自服務(wù)器端的消息返回 ,意思就是結(jié)束msg信息的寫(xiě)入
            input = socket.getInputStream();
            byte[] b = new byte[1024];
            int len = -1;
            sb = new StringBuffer();
            while ((len = input.read(b)) != -1) {
                sb.append(new String(b, 0, len, Charset.forName("UTF-8")));// 得到返回信息
            }
        } catch (Exception e) {
            callListener.onError();//請(qǐng)求失敗的回調(diào)
            e.printStackTrace();
        } finally {
            try {
                if (socket != null) {
                    output.flush();
                String jsonResult = sb.substring(8);//截取服務(wù)器返回的數(shù)據(jù)
                callListener.onResult(jsonResult);//請(qǐng)求成功的回調(diào)
                    socket.close();// 釋放資源,關(guān)閉這個(gè)Socket
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

所用到的工具類(lèi)

/**
 * Created by lexwu on 2017/1/23.
 * HttpUtil所用到的工具類(lèi)
 */

public class ByteUtil {
    /**
     * 將2個(gè)byte數(shù)組進(jìn)行拼接
     */
    public static byte[] addBytes(byte[] data1, byte[] data2) {
        byte[] data3 = new byte[data1.length + data2.length];
        System.arraycopy(data1, 0, data3, 0, data1.length);
        System.arraycopy(data2, 0, data3, data1.length, data2.length);
        return data3;
    }

    /**
     * int轉(zhuǎn)byte{}
     */
    public static byte[] intToBytes(int value, ByteOrder mode) {
        byte[] src = new byte[4];
        if (mode == ByteOrder.LITTLE_ENDIAN) {
            src[3] = (byte) ((value >> 24) & 0xFF);
            src[2] = (byte) ((value >> 16) & 0xFF);
            src[1] = (byte) ((value >> 8) & 0xFF);
            src[0] = (byte) (value & 0xFF);
        } else {
            src[0] = (byte) ((value >> 24) & 0xFF);
            src[1] = (byte) ((value >> 16) & 0xFF);
            src[2] = (byte) ((value >> 8) & 0xFF);
            src[3] = (byte) (value & 0xFF);
        }
        return src;
    }


    /**
     * 16進(jìn)制表示的字符串轉(zhuǎn)換為字節(jié)數(shù)組
     *
     * @param s 16進(jìn)制表示的字符串
     * @return byte[] 字節(jié)數(shù)組
     */
    public static byte[] hexStringToByteArray(String s) {
        int len = s.length();
        byte[] b = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            // 兩位一組,表示一個(gè)字節(jié),把這樣表示的16進(jìn)制字符串,還原成一個(gè)字節(jié)
            b[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character
                    .digit(s.charAt(i + 1), 16));
        }
        return b;
    }
}

網(wǎng)絡(luò)請(qǐng)求接口

/**
 * Created by lexwu on 2017/1/23.
 * 網(wǎng)絡(luò)請(qǐng)求接口回調(diào)
 */
public interface CallListener {
    void onResult(String jsonresult);
    void onError();
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容