Переглянути джерело

增加长度字段粘拆包解析规则

zhouhao 2 роки тому
батько
коміт
b32d2fddbc

+ 1 - 0
jetlinks-components/network-component/tcp-component/src/main/java/org/jetlinks/community/network/tcp/parser/DefaultPayloadParserBuilder.java

@@ -25,6 +25,7 @@ public class DefaultPayloadParserBuilder implements PayloadParserBuilder, BeanPo
         register(new DelimitedPayloadParserBuilder());
         register(new DelimitedPayloadParserBuilder());
         register(new ScriptPayloadParserBuilder());
         register(new ScriptPayloadParserBuilder());
         register(new DirectPayloadParserBuilder());
         register(new DirectPayloadParserBuilder());
+        register(new LengthFieldPayloadParserBuilder());
     }
     }
     @Override
     @Override
     public Supplier<PayloadParser> build(PayloadParserType type, ValueObject configuration) {
     public Supplier<PayloadParser> build(PayloadParserType type, ValueObject configuration) {

+ 85 - 0
jetlinks-components/network-component/tcp-component/src/main/java/org/jetlinks/community/network/tcp/parser/LengthFieldPayloadParserBuilder.java

@@ -0,0 +1,85 @@
+package org.jetlinks.community.network.tcp.parser;
+
+import io.vertx.core.buffer.Buffer;
+import lombok.SneakyThrows;
+import org.jetlinks.community.ValueObject;
+import org.jetlinks.community.network.tcp.parser.strateies.PipePayloadParser;
+
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+/**
+ * 长度字段粘拆包解析规则, 使用指定的字节数据来表示接下来的包长度.
+ *
+ * @author zhouhao
+ * @since 1.0
+ */
+public class LengthFieldPayloadParserBuilder implements PayloadParserBuilderStrategy {
+    @Override
+    public PayloadParserType getType() {
+        return PayloadParserType.LENGTH_FIELD;
+    }
+
+    @Override
+    @SneakyThrows
+    public Supplier<PayloadParser> buildLazy(ValueObject config) {
+        //偏移量
+        int offset = config.getInt("offset")
+                           .orElse(0);
+
+        //包长度
+        int len = config.getInt("length")
+                        .orElseGet(() -> config
+                            .getInt("to")
+                            .orElse(4) - offset);
+
+        //是否为小端模式
+        boolean le = config.getBoolean("little")
+                           .orElse(false);
+
+        int initLength = offset + len;
+
+        Function<Buffer, Integer> lengthParser;
+        switch (len) {
+            case 1:
+                lengthParser = buffer -> (int) buffer.getUnsignedByte(offset);
+                break;
+            case 2:
+                lengthParser =
+                    le ? buffer -> buffer.getUnsignedShort(offset)
+                        : buffer -> buffer.getUnsignedShort(offset);
+                break;
+            case 3:
+                lengthParser =
+                    le ? buffer -> buffer.getUnsignedMediumLE(offset)
+                        : buffer -> (int) buffer.getUnsignedMedium(offset);
+                break;
+            case 4:
+                lengthParser =
+                    le ? buffer -> buffer.getIntLE(offset)
+                        : buffer -> (int) buffer.getInt(offset);
+                break;
+            case 8:
+                lengthParser =
+                    le ? buffer -> (int) buffer.getLongLE(offset)
+                        : buffer -> (int) buffer.getLong(offset);
+                break;
+            default:
+                throw new IllegalArgumentException("illegal length:" + len);
+        }
+
+
+        return () -> new PipePayloadParser()
+            //先读取初始长度
+            .fixed(initLength)
+            .handler((buffer, parser) -> {
+                //获取长度字段,然后读取接下来的长度
+                int next = lengthParser.apply(buffer);
+                parser.result(buffer)
+                      .fixed(next);
+            })
+            .handler((buffer, parser) -> parser
+                .result(buffer)
+                .complete());
+    }
+}

+ 3 - 2
jetlinks-components/network-component/tcp-component/src/main/java/org/jetlinks/community/network/tcp/parser/PayloadParserType.java

@@ -22,10 +22,11 @@ public enum PayloadParserType implements EnumDict<String> {
      * @see ScriptPayloadParserBuilder
      * @see ScriptPayloadParserBuilder
      * @see PipePayloadParser
      * @see PipePayloadParser
      */
      */
-    SCRIPT("自定义脚本")
+    SCRIPT("自定义脚本"),
+    LENGTH_FIELD("长度字段"),
     ;
     ;
 
 
-    private String text;
+    private final String text;
     @Override
     @Override
     public String getValue() {
     public String getValue() {
         return name();
         return name();