先羅列一小段代碼,這一小段代碼代表瞭通信框架中發送請求的基本方式,讀者可以根據這段代碼,分析整個請求過程:
view plaincopy to clipboardprint?/**
* 典型使用方式:
*
* StructRequest output = new StructRequest(GameConst.COMM_PRICECOUNT_DATA);//GameConst.COMM_PRICECOUNT_DATA是請求ID,作用有兩個:用於服務器端識別請求,用於UI線程解析數據
*
* output.writeString("");//請求數據
*
* StructRequest output_time = new StructRequest(GameConst.COMM_SERVER_TIME);
*
* output_time.writeInt(0);
*
* StructRequest[] temp = { output, output_time };
*
* Request request = new Request(temp, this.screenId);//依靠Request對象封裝為請求
*
* sendRequest(request);//發送請求{這裡是耦合點,註意,發送請求的時候,程序的控制類[UI和網絡的耦合類]會記錄下請求的屏幕ID,用於解析}
*
* output.cloese();//關閉讀寫
*/
/**
* 典型使用方式:
*
* StructRequest output = new StructRequest(GameConst.COMM_PRICECOUNT_DATA);//GameConst.COMM_PRICECOUNT_DATA是請求ID,作用有兩個:用於服務器端識別請求,用於UI線程解析數據
*
* output.writeString("");//請求數據
*
* StructRequest output_time = new StructRequest(GameConst.COMM_SERVER_TIME);
*
* output_time.writeInt(0);
*
* StructRequest[] temp = { output, output_time };
*
* Request request = new Request(temp, this.screenId);//依靠Request對象封裝為請求
*
* sendRequest(request);//發送請求{這裡是耦合點,註意,發送請求的時候,程序的控制類[UI和網絡的耦合類]會記錄下請求的屏幕ID,用於解析}
*
* output.cloese();//關閉讀寫
*/
下面羅列StructRequest 類代碼,代碼中有詳細註釋,就不多敘述瞭。
view plaincopy to clipboardprint?package app.http;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Vector;
import app.program.Globe;
/**
* 功能:把各種類型的數據,轉換為字節數組。
*
* 屬於工具類,為網絡連接,本地數據存儲提供從其他數據類型到字節數據類型的轉換。
*
* 註意有些方法中包含瞭私有項目的網絡協議,並沒有刪除。比如writeInts2中writeLength(v[0].length);
*/
public class StructRequest {
private ByteArrayOutputStream bout;
private DataOutputStream out;
private int commID;
private boolean bTradeCipher;
/**
* 默認為非加密通訊
*
* @param commID
* int
*/
public StructRequest(int commID) {
this();
this.commID = commID;
bTradeCipher = false;
}
/**
* @param commID
* int
* @param bTradeCipher
* boolean 表示是否需要加密
*/
public StructRequest(int commID, boolean bTradeCipher) {
this();
this.commID = commID;
this.bTradeCipher = bTradeCipher;
}
public StructRequest() {
bout = new ByteArrayOutputStream();
out = new DataOutputStream(bout);
}
public void writeLength(int v) {
writeShort(v);
}
public void writeBoolean(boolean v) {
try {
out.writeBoolean(v);
} catch (Exception ex) {
throw new RuntimeException();
}
}
public void writeBooleans(boolean[] v) {
writeLength(v.length);
for (int i = 0; i < v.length; i++) {
writeBoolean(v[i]);
}
}
public void writeBooleans2(boolean[][] v) {
writeLength(v.length);
if (v.length > 0) {
writeLength(v[0].length);
for (int i = 0; i < v.length; i++) {
for (int j = 0; j < v[0].length; j++) {
writeBoolean(v[i][j]);
}
}
}
}
public void writeByte(int v) {
try {
out.writeByte(v);
} catch (Exception ex) {
throw new RuntimeException();
}
}
public void writeBytes(int[] v) {
writeLength(v.length);
for (int i = 0; i < v.length; i++) {
writeByte(v[i]);
}
}
public void writeBytes2(int[][] v) {
writeLength(v.length);
if (v.length > 0) {
writeLength(v[0].length);
for (int i = 0; i < v.length; i++) {
for (int j = 0; j < v[0].length; j++) {
writeByte(v[i][j]);
}
}
}
}
public void writeShort(int v) {
try {
out.write((v >>> 0) & 0xff);
out.write((v >>> 8) & 0xff);
} catch (Exception ex) {
throw new RuntimeException();
}
}
public void writeShorts(int[] v) {
writeLength(v.length);
for (int i = 0; i < v.length; i++) {
writeShort(v[i]);
}
}
public void writeShorts2(int[][] v) {
writeLength(v.length);
if (v.length > 0) {
writeLength(v[0].length);
for (int i = 0; i < v.length; i++) {
for (int j = 0; j < v[0].length; j++) {
writeShort(v[i][j]);
}
}
}
}
public void writeInt(int v) {
try {
out.write((v >>> 0) & 0xff);
out.write((v >>> 8) & 0xff);
out.write((v >>> 16) & 0xff);
out.write((v >>> 24) & 0xff);
} catch (Exception ex) {
throw new RuntimeException();
}
}
public void writeInts(int[] v) {
writeLength(v.length);
for (int i = 0; i < v.length; i++) {
writeInt(v[i]);
}
}
public void writeInts2(int[][] v) {
writeLength(v.length);
if (v.length > 0) {
writeLength(v[0].length);
for (int i = 0; i < v.length; i++) {
for (int j = 0; j < v[0].length; j++) {
writeInt(v[i][j]);
}
}
}
}
private int getSize(int limit) {
if (limit >= -128 && limit <= 127) {
return 1;
}
if (limit >= -32768 && limit <= 32767) {
return 2;
}
return 4;
}
public void writeNumbers(int[] v, int limit) {
int size = getSize(limit);
writeByte(size);
if (size == 1) {
writeBytes(v);
} else if (size == 2) {
writeShorts(v);
} else {
writeInts(v);
}
}
public void writeNumbers2(int[][] v, int limit) {
int size = getSize(limit);
writeByte(size);
if (size == 1) {
writeBytes2(v);
} else if (size == 2) {
writeShorts2(v);
} else {
writeInts2(v);
}
}
public void writeLong(long v) {
try {
out.write(((int) v >>> 0) & 0xff);
out.write(((int) v >>> 8) & 0xff);
out.write(((int) v >>> 16) & 0xff);
out.write(((int) v >>> 24) & 0xff);
out.write(((int) v >>> 32) & 0xff);
out.write(((int) v >>> 40) & 0xff);
out.write(((int) v >>> 48) & 0xff);
out.write(((int) v >>> 56) & 0xff);
} catch (Exception ex) {
throw new RuntimeException();
}
}
public void writeStringTrade(String v) {
try {
byte[] tmp = v.getBytes("UTF-8");
out.write(tmp);
} catch (Exception ex1) {
}
}
public void writeString(String v) {
try {
byte[] tmp = v.getBytes("UTF-8");
writeLength(tmp.length);
out.write(tmp);
} catch (Exception ex1) {
}
}
public void writeStringArray(String[] v) {
for (int i = 0; i < v.length; i++) {
writeString(v[i]);
}
}
public void writeStrings(String[] v) {
writeLength(v.length);
for (int i = 0; i < v.length; i++) {
writeString(v[i]);
}
}
public void writeStrings2(String[][] v) {
writeLength(v.length);
for (int i = 0; i < v.length; i++) {
writeStrings(v[i]);
}
}
public void writeByteArray(byte[] v) {
writeLength(v.length);
for (int i = 0; i < v.length; i++) {
writeByte(v[i]);
}
}
public void writeByteArray2(byte[] v) {
for (int i = 0; i < v.length; i++) {
writeByte(v[i]);
}
}
public int getType() {
return commID;
}
/**
* 此方法可以實現對程序數據的加密
*/
public byte[] getBytes() {
if (!bTradeCipher) {
return bout.toByteArray();
} else {
byte[] data = bout.toByteArray();
for (int i = 0; i < data.length; i++) {
data[i] = (byte) (data[i] ^ Globe.key[i % Globe.key.length]);
}
return data;
}
}
public void writeVector(Vector v) {
int num = v.size();
writeLength(num);
for (int i = 0; i < num; i++) {
writeString((String) v.elementAt(i));
}
}
public void cloese() {
try {
if (out != null) {
out.close();
}
if (bout != null) {
bout.close();
}
out = null;
bout = null;
} catch (IOException ex) {
}
}
}
package app.http;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Vector;
import app.program.Globe;
/**
* 功能:把各種類型的數據,轉換為字節數組。
*
* 屬於工具類,為網絡連接,本地數據存儲提供從其他數據類型到字節數據類型的轉換。
*
* 註意有些方法中包含瞭私有項目的網絡協議,並沒有刪除。比如writeInts2中writeLength(v[0].length);
*/
public class StructRequest {
private ByteArrayOutputStream bout;
private DataOutputStream out;
private int commID;
private boolean bTradeCipher;
/**
* 默認為非加密通訊
*
* @param commID
* int
*/
public StructRequest(int commID) {
this();
this.commID = commID;
bTradeCipher = false;
}
/**
* @param commID
* int
* @param bTradeCipher
* boolean 表示是否需要加密
*/
public StructRequest(int commID, boolean bTradeCipher) {
this();
this.commID = commID;
this.bTradeCipher = bTradeCipher;
}
public StructRequest() {
bout = new ByteArrayOutputStream();
out = new DataOutputStream(bout);
}
public void writeLength(int v) {
writeShort(v);
}
public void writeBoolean(boolean v) {
try {
out.writeBoolean(v);
} catch (Exception ex) {
throw new RuntimeException();
}
}
public void writeBooleans(boolean[] v) {
writeLength(v.length);
for (int i = 0; i < v.length; i++) {
writeBoolean(v[i]);
}
}
public void writeBooleans2(boolean[][] v) {
writeLength(v.length);
if (v.length > 0) {
writeLength(v[0].length);
for (int i = 0; i < v.length; i++) {
for (int j = 0; j < v[0].length; j++) {
writeBoolean(v[i][j]);
}
}
}
}
public void writeByte(int v) {
try {
out.writeByte(v);
} catch (Exception ex) {
throw new RuntimeException();
}
}
public void writeBytes(int[] v) {
writeLength(v.length);
for (int i = 0; i < v.length; i++) {
writeByte(v[i]);
}
}
public void writeBytes2(int[][] v) {
writeLength(v.length);
if (v.length > 0) {
writeLength(v[0].length);
for (int i = 0; i < v.length; i++) {
for (int j = 0; j < v[0].length; j++) {
writeByte(v[i][j]);
}
}
}
}
public void writeShort(int v) {
try {
out.write((v >>> 0) & 0xff);
out.write((v >>> 8) & 0xff);
} catch (Exception ex) {
throw new RuntimeException();
}
}
public void writeShorts(int[] v) {
writeLength(v.length);
for (int i = 0; i < v.length; i++) {
writeShort(v[i]);
}
}
public void writeShorts2(int[][] v) {
writeLength(v.length);
if (v.length > 0) {
writeLength(v[0].length);
for (int i = 0; i < v.length; i++) {
for (int j = 0; j < v[0].length; j++) {
writeShort(v[i][j]);
}
}
}
}
public void writeInt(int v) {
try {
out.write((v >>> 0) & 0xff);
out.write((v >>> 8) & 0xff);
out.write((v >>> 16) & 0xff);
out.write((v >>> 24) & 0xff);
} catch (Exception ex) {
throw new RuntimeException();
}
}
public void writeInts(int[] v) {
writeLength(v.length);
for (int i = 0; i < v.length; i++) {
writeInt(v[i]);
}
}
public void writeInts2(int[][] v) {
writeLength(v.length);
if (v.length > 0) {
writeLength(v[0].length);
for (int i = 0; i < v.length; i++) {
for (int j = 0; j < v[0].length; j++) {
writeInt(v[i][j]);
}
}
}
}
private int getSize(int limit) {
if (limit >= -128 && limit <= 127) {
return 1;
}
if (limit >= -32768 && limit <= 32767) {
return 2;
}
return 4;
}
public void writeNumbers(int[] v, int limit) {
int size = getSize(limit);
writeByte(size);
if (size == 1) {
writeBytes(v);
} else if (size == 2) {
writeShorts(v);
} else {
writeInts(v);
}
}
public void writeNumbers2(int[][] v, int limit) {
int size = getSize(limit);
writeByte(size);
if (size == 1) {
writeBytes2(v);
} else if (size == 2) {
writeShorts2(v);
} else {
writeInts2(v);
}
}
public void writeLong(long v) {
try {
out.write(((int) v >>> 0) & 0xff);
out.write(((int) v >>> 8) & 0xff);
out.write(((int) v >>> 16) & 0xff);
out.write(((int) v >>> 24) & 0xff);
out.write(((int) v >>> 32) & 0xff);
out.write(((int) v >>> 40) & 0xff);
out.write(((int) v >>> 48) & 0xff);
out.write(((int) v >>> 56) & 0xff);
} catch (Exception ex) {
throw new RuntimeException();
}
}
public void writeStringTrade(String v) {
try {
byte[] tmp = v.getBytes("UTF-8");
out.write(tmp);
} catch (Exception ex1) {
}
}
public void writeString(String v) {
try {
byte[] tmp = v.getBytes("UTF-8");
writeLength(tmp.length);
out.write(tmp);
} catch (Exception ex1) {
}
}
public void writeStringArray(String[] v) {
for (int i = 0; i < v.length; i++) {
writeString(v[i]);
}
}
public void writeStrings(String[] v) {
writeLength(v.length);
for (int i = 0; i < v.length; i++) {
writeString(v[i]);
}
}
public void writeStrings2(String[][] v) {
writeLength(v.length);
for (int i = 0; i < v.length; i++) {
writeStrings(v[i]);
}
}
public void writeByteArray(byte[] v) {
writeLength(v.length);
for (int i = 0; i < v.length; i++) {
writeByte(v[i]);
}
}
public void writeByteArray2(byte[] v) {
for (int i = 0; i < v.length; i++) {
writeByte(v[i]);
}
}
public int getType() {
return commID;
}
/**
* 此方法可以實現對程序數據的加密
*/
public byte[] getBytes() {
if (!bTradeCipher) {
return bout.toByteArray();
} else {
byte[] data = bout.toByteArray();
for (int i = 0; i < data.length; i++) {
data[i] = (byte) (data[i] ^ Globe.key[i % Globe.key.length]);
}
return data;
}
}
public void writeVector(Vector v) {
int num = v.size();
writeLength(num);
for (int i = 0; i < num; i++) {
writeString((String) v.elementAt(i));
}
}
public void cloese() {
try {
if (out != null) {
out.close();
}
if (bout != null) {
bout.close();
}
out = null;
bout = null;
} catch (IOException ex) {
}
}
}
下面羅列Request的代碼,註意裡面的請求方式分為兩種,第一種是一次隻請求一種數據,第二種是一次請求多種數據(這種方式有效的減少瞭請求的次數):
view plaincopy to clipboardprint?package app.http;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
* 功能:
*
* 把需要發送的內容,再次經過私有協議封裝,合並為一個Request對象,並且給這個對象一個和屏幕一致的ID,用於接收和解析數據
*
* 其他參照StructRequest
*/
public class Request {
private byte[] content = null;
private int screenId = 0;
private static final byte START_FLAG = (byte) '{';
private static final byte END_FLAG = (byte) '}';
private static final byte OTHER_FLAG = (byte) ':';
private boolean bTrade = false;
/**
* 單個通訊
*
* @param output
* StructOutput
*/
public Request(StructRequest output, int screeID) {
screenId = screeID;
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
out.write(START_FLAG); // 標識符
out.write(output.getType() & 0xFF);
out.write((output.getType() >>> 8) & 0xFF);
out.write(0);
out.write(0);
out.write(output.getBytes().length & 0xFF);
out.write((output.getBytes().length >>> 8) & 0xFF);
out.write(output.getBytes());
out.write(END_FLAG); // 校驗符
} catch (Exception ex) {
}
content = out.toByteArray();
try {
out.close();
} catch (IOException ex1) {
}
out = null;
}
public Request(int screeID) {
screenId = screeID;
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
out.write(START_FLAG); // 標識符
out.write(0);
out.write(0);
out.write(0);
out.write(0);
out.write(0);
out.write(0);
out.write(END_FLAG); // 校驗符
} catch (Exception ex) {
}
content = out.toByteArray();
try {
out.close();
} catch (IOException ex1) {
}
out = null;
}
/**
* 多個通訊
*
* @param output
* StructOutput[]
*/
public Request(StructRequest[] output, int screeID) {
screenId = screeID;
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
out.write(START_FLAG); // 標識符
for (int i = 0; i < output.length; i++) {
out.write(output[i].getType() & 0xFF);
out.write((output[i].getType() >>> 8) & 0xFF);
out.write(0);
out.write(0);
out.write(output[i].getBytes().length & 0xFF);
out.write((output[i].getBytes().length >>> 8) & 0xFF);
out.write(output[i].getBytes());
if (i < output.length – 1) {
out.write(OTHER_FLAG);
}
}
out.write(END_FLAG); // 校驗符
} catch (Exception ex) {
}
content = out.toByteArray();
try {
out.close();
} catch (IOException ex1) {
}
out = null;
}
public int getScreenId() {
return screenId;
}
public byte[] getContent() {
return content;
}
public void sedIsTrade(boolean trade) {
this.bTrade = trade;
}
public boolean getIsTrade() {
return this.bTrade;
}
}
package app.http;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
* 功能:
*
* 把需要發送的內容,再次經過私有協議封裝,合並為一個Request對象,並且給這個對象一個和屏幕一致的ID,用於接收和解析數據
*
* 其他參照StructRequest
*/
public class Request {
private byte[] content = null;
private int screenId = 0;
private static final byte START_FLAG = (byte) '{';
private static final byte END_FLAG = (byte) '}';
private static final byte OTHER_FLAG = (byte) ':';
private boolean bTrade = false;
/**
* 單個通訊
*
* @param output
* StructOutput
*/
public Request(StructRequest output, int screeID) {
screenId = screeID;
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
out.write(START_FLAG); // 標識符
out.write(output.getType() & 0xFF);
out.write((output.getType() >>> 8) & 0xFF);
out.write(0);
out.write(0);
out.write(output.getBytes().length & 0xFF);
out.write((output.getBytes().length >>> 8) & 0xFF);
out.write(output.getBytes());
out.write(END_FLAG); // 校驗符
} catch (Exception ex) {
}
content = out.toByteArray();
try {
out.close();
} catch (IOException ex1) {
}
out = null;
}
public Request(int screeID) {
screenId = screeID;
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
out.write(START_FLAG); // 標識符
out.write(0);
out.write(0);
out.write(0);
out.write(0);
out.write(0);
out.write(0);
out.write(END_FLAG); // 校驗符
} catch (Exception ex) {
}
content = out.toByteArray();
try {
out.close();
} catch (IOException ex1) {
}
out = null;
}
/**
* 多個通訊
*
* @param output
* StructOutput[]
*/
public Request(StructRequest[] output, int screeID) {
screenId = screeID;
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
out.write(START_FLAG); // 標識符
for (int i = 0; i < output.length; i++) {
out.write(output[i].getType() & 0xFF);
out.write((output[i].getType() >>> 8) & 0xFF);
out.write(0);
out.write(0);
out.write(output[i].getBytes().length & 0xFF);
out.write((output[i].getBytes().length >>> 8) & 0xFF);
out.write(output[i].getBytes());
if (i < output.length – 1) {
out.write(OTHER_FLAG);
}
}
out.write(END_FLAG); // 校驗符
} catch (Exception ex) {
}
content = out.toByteArray();
try {
out.close();
} catch (IOException ex1) {
}
out = null;
}
public int getScreenId() {
return screenId;
}
public byte[] getContent() {
return content;
}
public void sedIsTrade(boolean trade) {
this.bTrade = trade;
}
public boolean getIsTrade() {
return this.bTrade;
}
}
補充說明:在通信的時候,有兩種ID,首先是屏幕ID(本文第一段代碼中的this.screenId),這個ID用來確定請求的屏幕,以便請求結束以後,由這個屏幕來解析響應。其次是請求ID(本文第一段代碼中的GameConst.COMM_PRICECOUNT_DATA)。
為瞭便於讀者理解,下面一段代碼展示典型的響應解析方式:
view plaincopy to clipboardprint?public void httpCompleted(Response resp) {
byte[] tmp = resp.getData(GameConst.COMM_DATA);//這裡就根據請求ID來解析響應
if (tmp != null) {
}
}
public void httpCompleted(Response resp) {
byte[] tmp = resp.getData(GameConst.COMM_DATA);//這裡就根據請求ID來解析響應
if (tmp != null) {
}
}
下一篇講解請求的發送和響應的接收。
作者“馮小衛”