【发布时间】:2014-07-11 06:43:01
【问题描述】:
我正在使用一个简单的二进制协议。每个数据包由 10 个字节组成。第一个字节指定数据包类型。使用了许多(约 50 种)数据包类型。
我想为此协议编写一个独立于数据包处理的通用解析器。因此解析器应该检测数据包类型并将数据放入适当的数据包类的实例中,该实例保存协议数据。例如,考虑以下类:当解析器检测到数据包类型 1 --> new Type1() 并读取原始字节并设置温度和湿度时。对于数据包类型 2 和所有其他数据包类型也是如此。
class Packet {
byte[] raw;
}
class Type1 extends Packet {
int temperature;
int humidity;
}
class Type2 extends Packet {
DateTime sunrise;
DateTime sunset;
}
由于数据包类型如此之多,但每个应用程序只使用很少,因此应该可以在解析开始之前注册某些类型。所有其他数据包类型都将被忽略。
我计划为每种数据包类型配备一个 PacketParser。可能,我也需要每种类型的处理程序类。例如:
abstract class Type1Parser {
abstract void handle(Type1 packet);
}
class Type1Parser extends PacketParser {
//how to use/set handler? how to pass packet to handler?
static public Type1Handler type1Handler = null;
@override
void parse(Packet input) {
if(type1Handler == null)
return;
Type1 packet = new Type1(input);
packet.temperature = byteToInt(input.raw, 0, 3);
packet.humidity = byteToInt(input.raw, 4, 7);
type1Handler.handle(packet);
}
}
如何连接解析器和处理程序?以上是一种天真的方法: 程序需要实现Type1Handler并设置静态变量Type1Parser.type1Handler。
那么主解析器可以如下所示:
class MainParser {
Type1Parser type1 = new Type1Parser();
Type2Parser type2 = new Type2Parser();
...
void parse(byte[] packet) {
switch(packet[0]) {
case 1: type1.parse(packet); break;
case 2: type2.parse(packet); break;
...
}
}
}
然而,这似乎是 1) 很多非常相似的代码行 2) 很多开销,因为所有数据包解析器都被实例化,并且每个数据包 parse() 都会被调用,即使没有注册处理程序。
任何想法如何改进此代码?
注意:解析对程序应该是透明的。解析代码应该留在“解析库”中。所以理想情况下,程序只“知道”类 TypeXHandler 和 TypeX。
【问题讨论】:
-
" 对于每个数据包 parse() 都被调用,即使没有注册处理程序。" - 至少,似乎有必要调用解析器来跳过输入流中的数据包字节。您可以通过跳过数据包长度来读取数据包类型并跳过其余的解析(我假设每种数据包类型都有固定长度)。
-
handler 是您想要传递数据包信息的代码部分吗?它应该做什么?
-
要摆脱
parse中的一些 重复,你不能做PacketParser parser;使用开关来确定和设置解析器,然后在开关外面做parser.parse(packet);?我知道这并不深刻,但确实减少了逐字记录。