【问题标题】:IO#ioctl mangling an argument ? (Ruby 2.1.3)IO#ioctl 修改参数? (红宝石 2.1.3)
【发布时间】:2014-11-15 01:55:53
【问题描述】:

似乎IO#ioctl 改变了第二个参数传递。

require "socket"

SIOCGIWESSID      = 0x8B1B
IW_ESSID_MAX_SIZE = 32

sock = Socket.new(Socket::AF_INET, Socket::SOCK_DGRAM, 0)
template = "a16pI2"
iwessid  = [ 'wlan0', ' ' * IW_ESSID_MAX_SIZE, IW_ESSID_MAX_SIZE, 1 ].pack(template)

iwessid_bak = iwessid.dup
p iwessid == iwessid_bak    # true

sock.ioctl(SIOCGIWESSID, iwessid)  # iwessid string changed after #ioctl

p iwessid == iwessid_bak    # false !
p iwessid, iwessid_bak      # iwessid is different, lot of zero chars \0x00
                            # appended to original content

这是预期的行为还是错误? 使用新的 Ruby 2.1.3 测试。

【问题讨论】:

    标签: ruby ruby-2.1


    【解决方案1】:

    这是预期的行为,否则您将如何获得您感兴趣的数据?

    Ruby 的 IO#ioctl 是平台自己的 ioctl 系统调用的一个相当薄的包装器。此系统调用(或其 C 包装器)接受整数选项和指向与该选项相关的数据结构(即结构)的指针,其中包含进出内核的数据(对于某些选项,它也可以接受整数)。因此,您设置了结构,使用指向该结构的指针作为参数进行 ioctl 调用,然后检查其中的更改以获取您需要的信息。

    Ruby 允许您将此结构体作为 Ruby 字符串传递,但它仍需要采用系统调用所期望的格式,因此您通常需要使用 pack。之后您可能需要在同一字符串上使用unpack 来提取您需要的数据。

    我对@9​​87654327@ 选项一无所知,但快速搜索后会发现mailing list thread 似乎使用与您相同(或相似)的示例。因为代码在ioctl 调用之后继续:

    interface, essid, len, flags = iwreq.unpack("a16pII")
    

    虽然细节不完全相同(unpack 格式略有不同,并且它们使用了不同的变量名),但它显示了您将如何获得所需的结果。

    【讨论】:

    • 感谢您的回答。我只是希望按值传递给方法的参数将保持不变(除了间接的,比如 Array 元素的情况)。复制应在#ioctl 内部执行,并检索数据并返回值作为方法的结果。考虑到对 Ruby 来说非常不规范。
    • @DavidUnric 我同意这是非常不寻常的 Ruby,但在 C 代码中相当常见。 IO#ioctl 似乎正试图密切关注底层的ioctl。有些调用确实会在 int 返回值中返回有用的信息。据我了解,ioctl 是相当低级和特定于平台的,即使在编写 C 时也是如此。我怀疑获得一个通用的 Ruby 类接口会很棘手。
    • 好的。我将您的答案标记为已接受,因为您是对的,这是一种故意行为。 IO#ioctl 方法的文档签名仅返回一个整数(retcode),并且没有来自请求的结果数据,因此可以存储的位置没有歧义。
    猜你喜欢
    • 2010-11-17
    • 1970-01-01
    • 2019-12-24
    • 2019-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-21
    • 1970-01-01
    相关资源
    最近更新 更多