Ruby BinData:根据前两个字节定义结构
我正在使用Ruby并尝试从TCP接口读取二进制数据。接收到的消息包含一个报头和一个有效负载。有效负载由来自报头的id确定 这是一个例子:Ruby BinData:根据前两个字节定义结构,ruby,bindata,Ruby,Bindata,我正在使用Ruby并尝试从TCP接口读取二进制数据。接收到的消息包含一个报头和一个有效负载。有效负载由来自报头的id确定 这是一个例子: class TCPmessage < BinData:: Record class PayloadType_1 < BinData::Record uint8 :payloadType_1 # more payload data end class PayloadType_2 < BinData::Record
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
我确信有另一种解决方案使用BinData gem中的复合类型(数组/选项),但我看不到它。鉴于我们对您的尝试知之甚少,我看不出您的操作方式有任何真正的错误 我会写得有点不同,但在功能上不会有太大区别:
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")
我不知道当问到这个问题时,BinData gem是否已经有了这个特性,但是对于声明性方法,您应该使用它的类型 对于您的情况,可能是这样:
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}]}
我试图做的是根据头值在运行时选择数组的类型。是的,我可以告诉你。我无法根据BinData的
Choice
方法中标题的值返回其他类。正如他们的文档所示,返回其中一种类型很容易。返回一个“外星人”类型没有文档记录,这是你需要的。令人遗憾的是,像这样的高质量答案没有得到更多的关注<代码>选择在这种情况下绝对是正确的选择。@amenthes这对于在问题被问了很长时间后给出的答案来说并不罕见。不过,我很高兴您发现它很有用。:-)非常好!我用力按下upvote按钮,结果应该是+20,但事实并非如此:D。当@danizgod找到这个答案时,他可能会接受这个答案!
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")
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}]}
# [...]
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
# [...]