由于服務(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();
}