规范信息就是让客户端和服务器之间发送的消息遵守一个规范,类似于一个协议。于是,建立一NetMessage类,其中给出消息的各种参数,规定只能发送NetMessage类。这样做可以方便读取和解析,可以从下面代码中体会到。
public class NetMessage {
//BIN为二进制类型信息,STR为字符串类型信息
public static final int BIN = 1;
public static final int STR = 0;
private ENetCommand command; //指定这个消息的指令
private String action; //指定这个信息的动作
private int type; //信息的类型
private int len; //信息的长度
//把传递的消息分为俩种类型:字符串类型和二进制数据。分别用strPara,binPara来存放。
private String strPara;
private byte[] binPara;
}
每次发送一个信息,都应该new一个NetMessage,通过一系列的set方法,把信息参数和内容放到这个NetMessage中。并且send()方法只能接受NetMessage类型的参数,这样就做到了信息的规范,即只能发送NetMessage类型。
重写这个类的toString方法,当一个NetMessage消息需要发送时,真正发送的其实是他的toStringh后的字符串
@Override
public String toString() {
StringBuffer buffer = new StringBuffer();
if(type == STR) {
if(strPara == null) {
strPara = "";
binPara = strPara.getBytes();
}
}
if(binPara == null) {
binPara = new byte[0];
}
buffer.append(command).append(".")
.append(action == null ?" ":action).append(".")
.append(type).append(".")
.append(len);
return buffer.toString();
}
注意看:并没有把内容append到最后,也就是说这里是不发送消息的内容的。
根据发送信息的格式,我们可以很轻松的解析信息的参数。
但是!解析不到消息的具体内容
public NetMessage(String message) {
int index = message.indexOf('.');
this.command = ENetCommand.valueOf(message.substring(0, index));
message = message.substring(index+1);
index = message.indexOf('.');
this.action = message.substring(0, index);
message = message.substring(index+1);
index = message.indexOf('.');
this.type = Integer.valueOf(message.substring(0, index));
message = message.substring(index+1);
index = message.indexOf('.');
this.len = Integer.valueOf(message.substring(0, index));
}
传输数据的类型有俩种,字符串类型和二进制类型,真实传输过程中,如果我们还要根据不同的类型制定俩套不同的传输方案,很愚蠢,所以我用一种通用方案。
即:让NetMessage中的strPara,binPara同步(字符串变成字符数组),只需要传输用来存放二进制数据的binPara。
传输过程:
发送信息
public void send(NetMessage message) {
if(connection == null) {
return;
}
DataOutputStream dos = connection.getDos();
if(dos == null) {
return;
}
try {
dos.writeUTF(message.toString()); //信息头
dos.write(message.getBinPara(), 0, message.getLen()); //信息具体内容
} catch (IOException e) {
//TODO
}
}
接收信息
public NetMessage receive() {
int restLen = 0;
int length = 0;
int off = 0;
if(connection == null) {
return null;
}
DataInputStream dis = connection.getDis();
if(dis == null) {
return null;
}
NetMessage message = null;
try {
message = new NetMessage(dis.readUTF()); //接收信息头
//根据信息头部给出的len定长接受接下来的信息
restLen = message.getLen();
byte[] arr = new byte[restLen];
while(restLen > 0) {
length = BUFFER_MAX > restLen ? restLen:BUFFER_MAX;
dis.read(arr,off,length);
off += length;
restLen -= length;
}
message.setBinPara(arr);
} catch (IOException e) {
//TODO
}
return message;
}
二进制数据的收发,需要解决的是数据的分组和数据长度不确定的问题。
采用数据头+数据的格式,类似于TCP/IP协议的格式,使信息能被很好解析。
对于很长的二进制数据,可以对他进行分组,每个分组都有一个独立的头,独立发送。