1

我正在尝试通过 UDP 发送一个非常长的二进制整数(大约 200 位)。当我尝试使用 Array 的 pack 方法时,它会抱怨我要转换的字符串太大。

我会以错误的方式解决这个问题吗?

ruby-1.8.7-p352 :003 > [0b1101001010101101111010100101010011010101010110010101010101010010010101001010101010101011101010101010101111010101010101010101].pack('i')
RangeError: bignum too big to convert into `unsigned long'
from (irb):3:in `pack'
from (irb):3

这个数字应该代表一个 DNS 查询数据包(这是用于家庭作业;我们不允许使用任何 DNS 库)。

4

2 回答 2

4

你需要把你的号码分成更小的部分。可能最好的是一次编码 32 位:

> num = 0b1101001010101101111010100101010011010101010110010101010101010010010101001010101010101011101010101010101111010101010101010101
=> 17502556204775004286774747314501014869
> low_1 = num & 0xFFFFFFFF
=> 2864534869
> low_2 = (num >> 32) & 0xFFFFFFFF
=> 625650362
> low_3 = (num >> 64) & 0xFFFFFFFF
=> 1297454421
> low_4 = (num >> 96) & 0xFFFFFFFF
=> 220913317
> (low_4 << 96) + (low_3 << 64) + (low_2 << 32) + low_1
=> 17502556204775004286774747314501014869
> msg = [low_4, low_3, low_2, low_1].pack("NNNN")
=> "\r*\336\245MU\225U%J\252\272\252\275UU"
> msg.unpack("NNNN").inject {|sum, elem| (sum << 32) + elem}
=> 17502556204775004286774747314501014869

我更喜欢32这里的位,因为您将它们打包在Network Byte Order中,这使得与其他平台的互操作更加容易。该pack()方法不提供网络字节顺序 64 位整数。(这并不奇怪,因为 POSIX 不提供 64 位例程。)

于 2011-11-20T08:24:49.270 回答
-1

Ruby 1.9.3 可以正常工作。

irb(main):001:0> [0b1101001010101101111010100101010011010101010110010101010101010010010101001010101010101011101010101010101111010101010101010101].pack('i')
=> "UU\xBD\xAA"
于 2011-11-20T08:15:25.960 回答