在Java中分离协议解析器和处理程序
我正在使用一个简单的二进制协议。每个数据包由10个字节组成。第一个字节指定数据包类型。使用了许多(~50)种数据包类型 我想为这个协议编写一个通用的解析器,它独立于数据包的处理。因此,解析器应该检测数据包类型,并将数据放入相应数据包类的实例中,该实例保存协议数据。例如,考虑以下类:当解析器检测到数据包类型1-->新类型1()并读取原始字节并设置温度和湿度时。类似地,对于数据包类型2和所有其他数据包类型在Java中分离协议解析器和处理程序,java,parsing,Java,Parsing,我正在使用一个简单的二进制协议。每个数据包由10个字节组成。第一个字节指定数据包类型。使用了许多(~50)种数据包类型 我想为这个协议编写一个通用的解析器,它独立于数据包的处理。因此,解析器应该检测数据包类型,并将数据放入相应数据包类的实例中,该实例保存协议数据。例如,考虑以下类:当解析器检测到数据包类型1-->新类型1()并读取原始字节并设置温度和湿度时。类似地,对于数据包类型2和所有其他数据包类型 class Packet { byte[] raw; } class Type1 ext
class Packet {
byte[] raw;
}
class Type1 extends Packet {
int temperature;
int humidity;
}
class Type2 extends Packet {
DateTime sunrise;
DateTime sunset;
}
由于数据包类型太多,但每个应用程序只使用很少的数据包类型,所以在开始解析之前,应该可以注册某些类型的数据包。忽略所有其他数据包类型
我计划为每种数据包类型提供一个数据包解析器。可能,我还需要为每种类型提供一个处理程序类。例如:
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。这个设计问题没有完美的答案,我不想假装我知道,但希望我对这个问题的本能方法能教会你一些你还不知道的东西!我看到代码中缺少的主要组件是泛型:
public interface Parser<T extends Packet> {
T parse(Packet packet);
}
public interface Handler<T extends Packet> {
void handle(T packet);
}
公共接口解析器{
T解析(数据包);
}
公共接口处理程序{
无效句柄(T包);
}
通过这种方式,您可以使用惰性静态初始化来管理您知道的数据包类型。我不会在这里完全充实代码,但给您一个想法:
public class TypeRegistry {
private static Map<Integer, TypeHandlerBundle<?>> typeHandlerBundles;
static <T> register(int typeNum, Class<T> clazz, Parser<T> parser, Handler<T> handler) {
// Make bundle, add to map
}
... void parse(Packet packet) {
if (typeHandlerBundles.containsKey((int) packet[0])) {
TypeHandlerBundle<?> bundle = typeHandlerBundles.get((int) packet[0]);
bundle.parseAndHandle(packet);
}
}
}
public class TypeHandlerBundle<T extends Packet> {
...
private final Parser<T> parser;
private final Handler<T> handler;
... void parseAndHandle(Packet packet) {
T parsedPacket = parser.parse(packet);
handler.handle(parsedPacket);
}
}
...
public class Type1Processor {
static {
TypeRegistry.register(1, Type1.class, TYPE1_PARSER, TYPE1_HANDLER);
}
// Definition of constants, implementation, etc.
// ...
}
公共类类型注册表{
私有静态映射包=typeHandlerBundles.get((int)数据包[0]);
bundle.parseAndHandle(包);
}
}
}
公共类TypeHandlerBundle{
...
私有最终解析器;
私人最终处理人;
…无效parseAndHandle(数据包){
T parsedPacket=parser.parse(数据包);
handler.handle(parsedPacket);
}
}
...
公共类Type1处理器{
静止的{
寄存器(1,Type1.class,Type1\u解析器,Type1\u处理程序);
}
//常量、实现等的定义。
// ...
}
===
我省略了:限定符、下级实现、错误检查、同步、主方法等。根据您的设置,静态初始化可能不是调用<代码> TyePrimeReals.Re登记的正确方法,因此您可以考虑列出类(UGH,但有其优点)的属性文件,或者主方法中的硬编码调用序列
因为这里的
解析器
和处理程序
都是功能接口,所以不要忘记可以用lambdas实现它们!这样可以节省大量代码。好吧,就像torquestomp回答一样,下面是我的代码:
interface Packet {
}
interface PacketParser<T extends Packet> {
Class<T> getPacketClass();
int getPacketId();
int getPacketLength();
Packet parse(byte[] raw, int offset);
}
interface PacketListener<T extends Packet> {
Class<T> getPacketClass();
void onPacket(T packet);
}
interface PacketParsersRegistry {
<T extends Packet> void registerPacketParser(PacketParser<T> packetParser);
<T extends Packet> void registerPacketListener(PacketListener<T> packetListener);
}
class PacketHandlers<T extends Packet> {
final PacketParser<T> parser;
PacketListener<T> listener;
PacketHandlers(PacketParser<T> parser) {
this.parser = parser;
}
void setListener(PacketListener<T> listener) {
this.listener = listener;
}
}
class MainParser implements PacketParsersRegistry {
private final HashMap<Class<?>, PacketHandlers<?>> handlers = new HashMap<>();
private final HashMap<Integer, PacketParser> parsers = new HashMap<>();
@Override
public <T extends Packet> void registerPacketParser(PacketParser<T> packetParser) {
parsers.put(packetParser.getPacketId(), packetParser);
Class<T> packetClass = packetParser.getPacketClass();
handlers.put(packetClass, new PacketHandlers<>(packetParser));
}
@Override
public <T extends Packet> void registerPacketListener(PacketListener<T> packetListener) {
//noinspection unchecked
PacketHandlers<T> handlers = (PacketHandlers<T>) this.handlers.get(packetListener.getPacketClass());
if (handlers != null) {
handlers.setListener(packetListener);
}
}
void parse(byte[] stream, int offset) {
while (offset < stream.length) {
int type = stream[offset];
PacketParser parser = parsers.get(type);
// parser m.b. != null here
PacketListener listener = (PacketListener) handlers.get(parser.getPacketClass());
if (listener != null) {
Packet packet = parser.parse(stream, offset);
//noinspection unchecked
listener.onPacket(packet);
}
offset += parser.getPacketLength();
}
}
}
接口包{
}
接口包解析器{
类getPacketClass();
int getPacketId();
int getPacketLength();
数据包解析(字节[]原始,整数偏移量);
}
接口包侦听器{
类getPacketClass();
无效数据包(T数据包);
}
接口PacketParsersRegistry{
无效注册表PacketParser(PacketParser-PacketParser);
无效RegisterPackageListener(PacketListener-PacketListener);
}
类PacketHandlers{
最终包解析器;
PacketListener监听器;
PacketHandlers(PacketParser){
this.parser=解析器;
}
void setListener(PacketListener侦听器){
this.listener=listener;
}
}
类MainParser实现PacketParsersRegistry{
private final HashMap>handlers=new HashMap();
私有最终HashMap解析器=新HashMap();
@凌驾
公共无效注册表PacketParser(PacketParser PacketParser){
put(packetParser.getPacketId(),packetParser);
类packetClass=packetParser.getPacketClass();
put(packetClass,newpackethandlers(packetParser));
}
@凌驾
公共无效注册表PacketListener(PacketListener PacketListener){
//未检查
PacketHandlers=(PacketHandlers)this.handlers.get(packetListener.getPacketClass());
if(处理程序!=null){
setListener(packetListener);
}
}
无效解析(字节[]流,int偏移量){
while(偏移量<流长度){
int type=流[偏移];
PacketParser=parsers.get(类型);
//解析器m.b.!=此处为空
PacketListener=(PacketListener)handlers.get(parser.getPacketClass());
if(侦听器!=null){
Packet Packet=parser.parse(流,偏移量);
//未检查
onPacket(packet);
}
offset+=parser.getPacketLength();
}
}
}
以下是您如何使用它:
class HumidityPacket implements Packet {}
public class Main {
public static void main(String[] args) {
MainParser parser = new MainParser();
//...
parser.registerPacketListener(new PacketListener<HumidityPacket>() {
@Override
public Class<HumidityPacket> getPacketClass() {
return HumidityPacket.class;
}
@Override
public void onPacket(HumidityPacket packet) {
// todo
}
});
}
}
类HumidityPacket实现数据包{}
公共班机{
公共静态void main(字符串[]args){
MainParser=newmainparser();
//...
registerPacketListener(新的PacketListener(){
@凌驾
公共类getPacketClass(){
返回HumidityPacket.class;
}
@凌驾
公共无效数据包(HumidityPacket数据包){
//待办事项
}
});
}
}
你是对的
package parser;
public abstract class TypeParser {
public abstract void parse(byte[] arr);
}
package parser.type;
import parser.TypeParser;
public class Type1Parser extends TypeParser{
public void parse(byte[] array){
// do with the bytes of array what you want
}
}
package parser.type;
import parser.TypeParser;
public class Type122Parser extends TypeParser {
public void parse(byte[] arr) {}
}
package parser;
import java.util.Vector;
public class MainParser {
private Vector<TypeParser> vecTypeParse=new Vector<TypeParser>();
public void parsePacket(byte[] array){
if(array==null || array.length<1) return; // or throw some exception
int typePacket=array[0]&0xff;
String s="parser.type.Type"+String.valueOf(typePacket)+"Parser";
TypeParser type=null;
try {
type=(TypeParser)Class.forName(s).newInstance(); //here you create class that you need
} catch(InstantiationException e) {e.printStackTrace();
} catch(IllegalAccessException e) {e.printStackTrace();
} catch(ClassNotFoundException e) {e.printStackTrace();}
// you can do something with the exceptons
if(type==null) return; // or throw some exception
type.parse(array); // here parse data for class you just created.
this.vecTypeParse.addElement(type);
}
}