先罗列一小段代码,这一小段代码代表了通信框架中发送请求的基本方式,读者可以根据这段代码,分析整个请求过程:
/**
* 典型使用方式:
*
* 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 类代码,代码中有详细注释,就不多叙述了。
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的代码,注意里面的请求方式分为两种,第一种是一次只请求一种数据,第二种是一次请求多种数据(这种方式有效的减少了请求的次数):
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)。
为了便于读者理解,下面一段代码展示典型的响应解析方式:
public void httpCompleted(Response resp) {
byte[] tmp = resp.getData(GameConst.COMM_DATA);//这里就根据请求ID来解析响应
if (tmp != null) {
}
}
下一篇讲解请求的发送和响应的接收。
ps:有任何疑问可以留言,回复可能不及时,但是有意义的疑问一定回复。
ps:记得看到好文章好顶……