3

你好男孩和女孩。

我正在开发一个基于终端的客户端应用程序,它通过 TCP/IP 与服务器通信并发送和接收任意数量的原始字节。每个字节代表一个命令,我需要将其解析为代表这些命令的 Java 类,以供进一步使用。

我的问题是如何有效地解析这些字节。我不想以一堆嵌套的 if 和 switch-case 告终。

我已经准备好这些命令的数据类。我只需要弄清楚进行解析的正确方法。

以下是一些示例规格:

字节流可以是例如整数:[1,24,2,65,26,18,3,0,239,19,0,14,0,42,65,110,110,97,32,109,121,121,106,228,42,15,20,5,149, 45,87]

第一个字节是 0x01,它是仅包含一个字节的标头的开始。

第二个是长度,它是某些命令中的字节数,这里也只有一个字节。

下一个可以是第一个字节是命令的任何命令,在这种情况下为 0x02,它跟在命令中包含的 n 个字节之后。

很快。最后有校验和相关的字节。

表示 set_cursor 命令的示例类:

/**
 * Sets the cursor position.
 * Syntax: 0x0E | position
 */
public class SET_CURSOR {

private final int hexCommand = 0x0e;
private int position;

public SET_CURSOR(int position) {

}

public int getPosition() {
    return position;
}

public int getHexCommnad() {
    return hexCommand;
}

}
4

4 回答 4

4

当像这样解析字节流时,最好使用的设计模式是命令模式。每个不同的命令都将充当处理程序来处理流中接下来的几个字节。

interface Command{

    //depending on your situation, 
    //either use InputStream if you don't know
    //how many bytes each Command will use
    // or the the commands will use an unknown number of bytes
    //or a large number of bytes that performance
    //would be affected by copying everything.
    void execute(InputStream in);

    //or you can use an array if the
    //if the number of bytes is known and small.
    void execute( byte[] data);

}

然后,您可以拥有一个映射,其中包含每个字节“操作码”的每个 Command 对象。

Map<Byte, Command> commands = ...

commands.put(Byte.parseByte("0x0e", 16), new SetCursorCommand() );
...

然后您可以解析消息并执行命令:

InputStream in = ... //our byte array as inputstream
byte header = (byte)in.read();
int length = in.read();
byte commandKey = (byte)in.read();   
byte[] data = new byte[length]
in.read(data);

Command command = commands.get(commandKey);
command.execute(data);

你可以在同一个字节消息中有多个命令吗?如果是这样,您可以轻松地将命令获取和解析包装在一个循环中,直到 EOF。

于 2013-09-13T14:47:24.710 回答
2

你可以试试那个https://github.com/raydac/java-binary-block-parser的 JBBP 库

@Bin class Parsed { byte header; byte command; byte [] data; int checksum;}
Parsed parsed = JBBPParser.prepare("byte header; ubyte len; byte command; byte [len] data; int checksum;").parse(theArray).mapTo(Parsed.class);
于 2014-08-11T06:13:54.017 回答
1

这是一个庞大而复杂的课题。

这取决于您将读取的数据类型。

  • 这是一个looooong流吗?
  • 是很多小的独立结构/对象吗?
  • 您的流程的结构/对象之间是否有一些引用?

我最近为专有软件编写了一个字节序列化/反序列化库。

我采用类似于访问者的方法进行类型转换,与 JAXB 的工作方式相同。

我将我的对象定义为 Java 类。在类上初始化解析器,然后将字节传递给它以进行反序列化或将 Java 对象传递给序列化。

类型检测(基于流程的第一个字节)通过简单的大小写匹配机制(1 => ClassA,15 => ClassF,...)向前完成。

编辑:它可能很复杂或代码重载(嵌入对象),但请记住,如今,java 对此进行了很好的优化,它使代码保持清晰易懂。

于 2013-09-13T12:15:55.963 回答
0

ByteBuffer可用于解析字节流 - Java 中 ByteBuffer 的用途是什么?

byte[] bytesArray = {4, 2, 6, 5, 3, 2, 1};
ByteBuffer bb = ByteBuffer.wrap(bytesArray);
int intFromBB = bb.order(ByteOrder.LITTLE_ENDIAN).getInt(); 
byte byteFromBB = bb.get(); 
short shortFromBB = bb.getShort(); 
于 2016-08-31T12:14:05.600 回答