我正在使用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中的复合类型(数组/选择)的解决方案,但我看不到它。
发布于 2015-02-21 07:24:11
我不知道当这个问题被问到时,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
# [...]发布于 2012-11-03 00:33:28
我看不出你的做法有什么问题,因为我们对你想做的事情知之甚少。
我会以不同的方式编写它,但在功能上不会有太大的不同:
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")https://stackoverflow.com/questions/13197878
复制相似问题