在Java中分离协议解析器和处理程序

在Java中分离协议解析器和处理程序,java,parsing,Java,Parsing,我正在使用一个简单的二进制协议。每个数据包由10个字节组成。第一个字节指定数据包类型。使用了许多(~50)种数据包类型 我想为这个协议编写一个通用的解析器,它独立于数据包的处理。因此,解析器应该检测数据包类型,并将数据放入相应数据包类的实例中,该实例保存协议数据。例如,考虑以下类:当解析器检测到数据包类型1-->新类型1()并读取原始字节并设置温度和湿度时。类似地,对于数据包类型2和所有其他数据包类型 class Packet { byte[] raw; } class Type1 ext

我正在使用一个简单的二进制协议。每个数据包由10个字节组成。第一个字节指定数据包类型。使用了许多(~50)种数据包类型

我想为这个协议编写一个通用的解析器,它独立于数据包的处理。因此,解析器应该检测数据包类型,并将数据放入相应数据包类的实例中,该实例保存协议数据。例如,考虑以下类:当解析器检测到数据包类型1-->新类型1()并读取原始字节并设置温度和湿度时。类似地,对于数据包类型2和所有其他数据包类型

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);     
        }

}