3

所以我在 GitHub 上 fork了这个 gem,认为我可以修复和更新它的一些问题,以便在 Rails 项目中使用。我基本上得到了这个输出:

irb(main):020:0> query = Query::simpleQuery('xx.xxx.xxx.xx', 25565)
=> [false, #<Encoding::CompatibilityError: incompatible character encodings: UTF-8 and ASCII-8BIT>]

irb(main):021:0> query = Query::simpleQuery('xx.xxx.xxx.xx', 25565)
=> {:motd=>"Craftnet", :gametype=>"SMP", :map=>"world", :numplayers=>"0", :maxplayers=>"48"}

第一个响应是编码错误的例子,第二个是想要的输出(IP 被取出)。基本上这是查询 Minecraft 服务器以获取有关它的信息。

我尝试使用

Encoding.default_external = Encoding::UTF_8
Encoding.default_internal = Encoding::UTF_8

但这只是给出了相同的响应,随机吐出编码错误而不是。

这是包含所有代码的相关 GitHub 存储库:RubyMinecraft

任何帮助将不胜感激。

4

1 回答 1

2

Query课堂上有这一行

@key = Array(key).pack('N')

这将创建一个带有 ASCII-8BIT 相关编码的字符串(即它是一个二进制字符串)。

后来@key这一行中使用:

query = @sock.send("\xFE\xFD\x00\x01\x02\x03\x04" + @key, 0)

在 Ruby 2.0 中,字符串文字的默认编码是 UTF-8,因此这是将 UTF-8 字符串与二进制字符串结合起来。

当 Ruby 尝试这样做时,它首先检查二进制字符串是否仅包含 7 位值(即所有字节都小于或等于 127,最高字节为 0),如果是,则认为它与UTF-8 将它们组合在一起,没有进一步的问题。如果不是,(即,如果它包含大于 127 的字节),那么这两个字符串不兼容并Encoding::CompatibilityError引发 an。

是否引发错误取决于 的内容@key,该内容是从服务器的响应中初始化的。有时这个值恰好只包含 7 位值,因此不会引发错误,而其他时候有一个字节设置了高位,因此会产生错误。这就是为什么错误看起来是“随机的”。

要修复它,您可以指定将两个字符串组合的行中的字符串文字视为二进制。最简单的方法是这样使用force_encoding

query = @sock.send("\xFE\xFD\x00\x01\x02\x03\x04".force_encoding(Encoding::ASCII_8BIT) + @key, 0)
于 2013-07-13T13:31:35.833 回答