最近在使用 ruby 进行与路由器交互的开发,路由硬件使用的 C 有没有 gem 能够很好的方便与 C 中的 struct 结构体进行交互,包括 send、recv ???
这两者都有对 C struct 的支持。Fiddle::CStruct 和 FFI::Struct. 具体使用参考其文档即可。
#3 楼 @mingle5566 这个当然也可以。用这个 gem bit-struct 或 gem cstruct(不是 Fiddle::CStruct)
仅为 示范性伪代码
require 'bit-struct'
class MyStruct < BitStruct
...
unsigned :id, 8, "id" # 8 意为 8bit,也就一个byte。一个int32类型,就是32。以此类推。
...
end
data = recv(...)
my_data = MyStruct.new(data)
puts my_data.id
#6 楼 @mingle5566 这个和结构体没关系吧,这是面向协议编程。解析协议我基本都用 erlang
.
#5 楼 @skandhas 那个 bit-struct 挺方便的啊。
或者自己进行位操作。例如 ruby 解析 websocket process_data
#7 楼 @mingle5566 不客气,能用上就 OK 了。 #9 楼 @flowerwrong 嗯,如果结构很简单,自己进行 位操作 和 unpack 也是不错的选择。
#10 楼 @skandhas 还有个问题请教一下,用 bit-struct 如何解析 char[128] 这种固定位数的值,例如:
###################C中我这样定义的
typedef unsigned char __u8;
typedef unsigned short __u16;
typedef unsigned int __u32;
typedef struct
{
__u16 order; /*表示连接认证时的交互顺序,由1开始逐1地递增。路由器与服务器间共享同一个order,比如:路由器order = 1, 服务器order = 2, 路由器order = 3, 目前最多到4*/
__u8 srv_type;
__u8 router_addr[128]; /*设备地址*/
}sentrtu;
sentrtu seru;
seru.order = htons(1025);
seru.srv_type = 'b';
strcpy(seru.router_addr, "abc");
####################ruby这样定义
class MyStruct < BitStruct
unsigned :order, 16, "order"
unsigned :srv_type, 8, "srv_type"
unsigned :router_addr, 16 * 8, "router_addr"
end
my_data = MyStruct.new(data)
puts my_data.order
puts my_data.srv_type.chr
puts my_data.router_addr
最后 router_addr 输入的是: 129445968641824014294637244265334308864 一串数字,这个是什么格式的?如何转换输入"abc"
#11 楼 @mingle5566 对于数组的处理用 vector, 不过 bit-struct 对 array 的 处理比较啰嗦。
require "bit-struct"
class SentRTU < BitStruct
unsigned :order, 16, 'order'
unsigned :srv_type, 8, 'srv-type'
vector :router_addr, "router_addr", :length => 128 do
unsigned :byte, 8
end
def set_router_addr(str)
if str.length > router_addr.size - 1
raise "str.length should be less than router_addr.size - 1"
end
# bit-struct 对 vector 的写入处理比较啰嗦,只能挨个赋值。
# 像这样是不行的:
# str.bytes.each_with_index {|byte, i| router_addr[i].byte = byte }
addr = self.router_addr
str.bytes.each_with_index do |byte, i|
v = addr[i]
v.byte = byte
addr[i] = v
end
self.router_addr = addr
end
end
a = SentRTU.new
a.set_router_addr('abcdef')
puts a.router_addr
类似的 gem 还有 binstruct, cstruct . 在使用类似的 gem 时,一定要注意 struct 的 alignment 与相应的 C struct 的 alignment 要一致,不然就不对了。