【问题标题】:Parse a DatagramPacket after converting it to a byte array in Java在将 DatagramPacket 转换为 Java 中的字节数组后解析它
【发布时间】:2012-05-27 12:49:26
【问题描述】:

我正在尝试解析我将在套接字处收到的 DatagramPacket。我知道我将收到的数据包的格式,即 DHCPREQUEST 数据包,但我认为这并不重要。为简单起见,我们只考虑前六个字段:

第一个字段是“操作码”,为 1 个字节。
第二个字段是 1 个字节的“硬件类型”。
三、“硬件地址长度”,1字节。
四、“跳”,1个字节。
五、“交易标识xid”,4字节。
第六,“秒”,2个字节。

收到数据包后,我的做法是转成字节数组。

DatagramPacket request = new DatagramPacket(new byte[1024], 1024);
socket.receive(request);
byte[] buf = request.getData();

此时,数据包作为一系列字节存储在字节数组buf中。既然我知道这个字节序列的结构是什么,那我该如何解析呢?一字节字段很简单,但是多位字段呢?例如,如何提取字节 4 到 7,并将它们存储在名为 xid 的变量中?

我可以手动将每个字节放入一个数组中:

byte[] xid = new byte[4];
xid[0] = buf[4];
xid[1] = buf[5];
xid[2] = buf[6];
xid[3] = buf[7];

但这对于数百字节长度的字段来说非常乏味且不切实际。 String 类可以解析给定偏移量和长度的子字符串; Java中的字节数组有类似的方法吗?

还是我以某种方式为难自己?

【问题讨论】:

  • 为什么不使用 TCP/IP 而不是 UDP?它允许更好的使用机制...
  • @Thihara:DHCP 使用 UDP 作为其传输协议。我决定使用 UDP 来模拟实际 DHCP 服务器的行为。
  • 虽然我不知道为什么 DHCP 不使用 TCP,这似乎是一个更可靠的协议。但我知道什么……哈哈。
  • @Terribad - 这是因为 DHCP 是一种轻量级协议,它不需要可靠的字节流语义以及所需的所有网络数据包和本地资源开销。 (查看 TCP 规范,计算启动和关闭连接所需的网络数据包。)

标签: java parsing udp bytearray


【解决方案1】:

将字节数组包装在 ByteArrayOutputStream 中;围绕它包装一个 DataInputStream;然后使用DataInputStream的方法。

【讨论】:

  • 我也是这么想的。你能举个小例子吗?
  • @Anand 我希望你能够直接从这个描述中编码
【解决方案2】:

做这样的事情最干净的方法可能是使用实用方法Arrays.copyOfRange

【讨论】:

  • 谢谢,我认为没有更简洁的方法,除了滚动像上面建议的@Stephen C 这样的自定义帮助方法。
  • 如果你有一个字节数组并且需要字节以外的东西,你可能需要将它与一些类似的辅助方法结合起来。
【解决方案3】:

您所做的是自己编写一些辅助方法来从数据包中提取 2 字节、4 字节等值,读取字节并将它们组装成 Java shortint 或任何值。

例如

    public short getShort(byte[] buffer, int offset) {
        return (short) ((buffer[offset] << 8) | buffer[offset + 1]);
    }

然后,您可以根据需要经常使用这些辅助方法。 (如果你想花哨的话,你可以让方法更新一个持有当前位置的属性,这样你就不必传递offset 参数。)


或者,如果您不担心开销,您可以将字节数组包装在ByteArrayInputStreamDataInputStream 中,并使用后者的API 来读取字节、短裤、整数等。 IIRC,DataInputStream 假设数字在流中以“网络字节顺序”表示......这几乎可以肯定是 DHCP 规范所要求的。

【讨论】:

  • 你能解释一下你的函数背后的逻辑吗?我以机械的方式看到,您将字节左移 8 位并将其与下一个数组索引中的字节进行 OR'ing(添加?),但我不了解此操作的重要性。
  • 它以非常直接的方式从一对字节中组装出short。拿一支铅笔和一张纸,用二进制写下数字,如果你不明白,就“手动执行”代码。
  • 所以我这样做了,这就是我所理解的:该函数获取[offset] 的字节并将其左移 8 位。由于字节大小为 8 位,并且左移不是循环的,所以无论buffer[offset] 的内容如何,​​buffer[offset] &lt;&lt; 8 都会产生00000000。然后你将这个00000000buffer[offset+1] 或,这总是产生buffer[offset+1]...?
  • 我现在明白了。我不知道 Java 中的位移操作总是返回一个 int,而不管操作数的类型如何。所以我认为左移,例如0000 0101 8 位会返回0000 0000,而实际上它会返回0000 0000 0000 0000 0000 0101 0000 0000
【解决方案4】:

我有点晚了,但是有一个 ByteBuffer 类:

ByteBuffer b = ByteBuffer.wrap(request.getData());

byte opcode = b.get();
byte hwtype = b.get();
byte hw_addr_len = b.get();
byte hops = b.get();
int xid = b.getInt();
short seconds = b.getShort();

或者,如果您只需要一个字段:

ByteBuffer b = ByteBuffer.wrap(request.getData());
int xid = b.getInt(4);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-12-27
    • 2011-07-02
    • 1970-01-01
    • 2011-12-21
    • 2010-11-18
    相关资源
    最近更新 更多