首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >BinData:根据前两个字节定义结构

BinData:根据前两个字节定义结构
EN

Stack Overflow用户
提问于 2012-11-02 23:06:01
回答 2查看 497关注 0票数 0

我正在使用Ruby并尝试从TCP接口读取二进制数据。接收到的消息包含报头和有效负载。有效载荷由来自报头的id确定。

这是一个示例:

代码语言:javascript
复制
class TCPmessage < BinData:: Record

  class PayloadType_1 < BinData::Record
    uint8 :payloadType_1
    # more payload data
  end

  class PayloadType_2 < BinData::Record
    uint8 :payloadType_2
    # more payload data
  end

  uint8 :payload_id

  array :payload, :type => <<Here I need to select "PayloadType_1" or "PayloadType_2" based on the "payload_id" from above>>, ...

end

我尝试了几个变体,但只想出了以下解决方案:

代码语言:javascript
复制
class TCPmessage < BinData:: Record

  class PayloadType_1 < BinData::Record
    uint8 :payload_id
    uint8 :payloadType_1
    # more payload data
  end

  class PayloadType_2 < BinData::Record
    uint8 :payload_id
    uint8 :payloadType_2
    # more payload data
  end

  uint8 :payload_id
end

在主程序中,我首先读取payload_id,然后使用case语句选择接下来要实例化的类:

代码语言:javascript
复制
x = TCPmessage.new
case x.read("TCPmessage").payload_id.to_s
when "1"
  y = TCPmessage::PayloadType_1.new
when "2"
  y = TCPmessage::PayloadType_2.new
end
y.read("TCPmessage")

我确信有另一个使用BinData gem中的复合类型(数组/选择)的解决方案,但我看不到它。

EN

回答 2

Stack Overflow用户

发布于 2015-02-21 07:24:11

我不知道当这个问题被问到时,BinData gem是否已经有了这个特性,但是对于声明性方法,您可能希望使用它的Choice类型。

对于您的情况,可能如下所示:

代码语言:javascript
复制
require 'bindata'

class PayloadType_1 < BinData::Record
  uint8 :type_one_byte
  # more payload data for type 1
end

class PayloadType_2 < BinData::Record
  uint8 :type_two_byte
  # more payload data for type 2
end

class TCPmessage < BinData::Record
  uint8 :payload_id
  choice :payload, selection: :payload_id do
    array 1, type: :payloadType_1, read_until: :eof
    array 2, type: :payloadType_2, read_until: :eof
  end
end

puts TCPmessage.read "\x01ABC" # {:payload_id=>1, :payload=>[{:type_one_byte=>65}, {:type_one_byte=>66}, {:type_one_byte=>67}]}
puts TCPmessage.read "\x02DEF" # {:payload_id=>2, :payload=>[{:type_two_byte=>68}, {:type_two_byte=>69}, {:type_two_byte=>70}]}

请注意,selection: :payload_idselection: lambda { payload_id }的快捷方式。因此,如果出于某种原因,您实际上需要通过字符串对选择进行索引,那么您可以

代码语言:javascript
复制
  # [...]
  choice :payload, selection: lambda { payload_id.to_s } do
    array "1", type: :payloadType_1, read_until: :eof
    array "2", type: :payloadType_2, read_until: :eof
  end
  # [...]
票数 2
EN

Stack Overflow用户

发布于 2012-11-03 00:33:28

我看不出你的做法有什么问题,因为我们对你想做的事情知之甚少。

我会以不同的方式编写它,但在功能上不会有太大的不同:

代码语言:javascript
复制
x = TCPmessage.new
y = case x.read("TCPmessage").payload_id
    when 1
      TCPmessage::PayloadType_1.new
    when 2
      TCPmessage::PayloadType_2.new
    end
y.read("TCPmessage")
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13197878

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档