移动开发中的通信架构(二)

 

先罗列一小段代码,这一小段代码代表了通信框架中发送请求的基本方式,读者可以根据这段代码,分析整个请求过程:

/**
 * 典型使用方式:
 * 
 * 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:记得看到好文章好顶……

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值