我正在使用Ruby并尝试从TCP接口读取二进制数据。收到的消息包含标头和有效负载。有效负载由标头中的id确定。
这是一个例子:
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
我尝试了一些变体,但只提出了以下解决方案:
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
语句选择下一个要实例化的类:
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的复合类型(数组/选项)的解决方案,但我看不到它。
答案 0 :(得分:1)
我不知道当问到这个问题时BinData gem是否已经有了这个功能,但对于声明式方法,你想要使用它的Choice类型。
对于你的情况,可能是这样的:
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_id
是selection: lambda { payload_id }
的快捷方式。因此,如果您确实需要出于某种原因按字符串索引选项,则可以
# [...]
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
# [...]
答案 1 :(得分:0)
我没有看到你做这件事的方式有什么问题,因为我们对你要做的事情知之甚少。
我的写法有点不同,但它在功能上并没有太大的区别:
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")