在Linux上检测python中连接到Raspberry Pi的无线设备

fra*_*gon 3 python linux shell network-programming raspberry-pi

在我的python代码中,我需要获取连接到Raspberry Pi的"物理"WiFi网络设备列表

我一直在这样做,致电:

raw_output = check_output('iw dev', shell=True)
Run Code Online (Sandbox Code Playgroud)

然后提取我需要的所有数据 raw_output

它工作正常,但在iw help其中说,Do NOT screenscrape this tool, we don't consider its output stable.以我的方式获取这些数据真的不安全吗?如果是,那么这样做的正确方法是什么?

jbm*_*jbm 8

"不要筛选此工具,我们不认为其输出稳定"的含义是,随着新版本的发布iw,输出格式化可能会发生变化.所以开发人员iw警告你,如果你根据输出的解析编写软件,它可能会在未来的版本中破坏iw.

以古老的ifconfig命令为例.多年来,它的输出过去常常如下形成:

eth0      Link encap:Ethernet  HWaddr 00:80:C8:F8:4A:51
          inet addr:192.168.99.35  Bcast:192.168.99.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:190312 errors:0 dropped:0 overruns:0 frame:0
          TX packets:86955 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:100 
          RX bytes:30701229 (29.2 Mb)  TX bytes:7878951 (7.5 Mb)
          Interrupt:9 Base address:0x5000
Run Code Online (Sandbox Code Playgroud)

虽然它被认为是稳定的(甚至被某些人弃用并且没有维护),但它在几年前发生了变化,现在看起来像这样:

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.1.67  netmask 255.255.255.0  broadcast 192.168.1.255
        inet6 fe80::8e89:a5ff:fe57:103c  prefixlen 64  scopeid 0x20<link>
        ether 8c:89:a5:57:10:3c  txqueuelen 1000  (Ethernet)
        RX packets 2219946  bytes 3178868967 (2.9 GiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 1241676  bytes 102998523 (98.2 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
Run Code Online (Sandbox Code Playgroud)

...所以让我说我做了一些软,通过搜索"HWaddr"之后的字符串来查看MAC地址.现在它会被打破,因为它应该在"ether"之后寻找字符串.

但只要你不更新iw,或定期测试你的工作,你就不应该遇到任何问题.

无论如何,解析第三方工具的输出总是有点脆弱,你只需要知道它.例如,输出可能取决于用户的LOCALE设置.现实生活中的例子,我ifconfig在一些用户环境中输出失败的一些脚本.根本原因:这是法语区域设置中的输出:

eth0      Lien encap:Ethernet  HWaddr 00:FF:F2:58:32:A1  
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          Packets reçus:0 erreurs:0 :0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 lg file transmission:1000 
          Octets reçus:0 (0.0 b) Octets transmis:0 (0.0 b)
          Interruption:23 Adresse de base:0x2000
Run Code Online (Sandbox Code Playgroud)

注意法语"Packetsreçus","erreurs"和"Octetsreçus"而不是"RX包","错误"和"RX字节".

编辑:

所以:

以我的方式获取这些数据真的不安全吗?

并不是的.您只需要记住,您的软件取决于某些第三方软件的输出字符串,这些软件有些超出您的控制范围,并且可能在将来发生变化.这将是您的定期测试和维护工作,没有任何悲剧,那就是软件生活.

如果是,那么这样做的正确方法是什么?

再次,"不",但如果你想要防范:不要依赖第三方软件的文本输出.这通常涉及编写自己的代码替换这些工具,它可以是一个相当的任务.如果这样做,你使用一些第三方库,好吧,库API也随着时间的推移而改变...... :-)

编辑2:

在你的情况下,不依赖于输出iw(即编写你自己的"迷你iw"),并考虑你想用Python编码:

在低级别iw,C libnl语言中的写入,使用(在C中也是如此)与内核通信以在网络接口上获取信息/执行操作.

https://www.infradead.org/~tgr/libnl/

你很幸运:似乎有一个Python libnl库的activealy维护版本.

https://pypi.python.org/pypi/libnl/0.2.0

所以计划是:

  1. 研究新的C源代码,了解它所执行的netlink/libnl操作,以获取/设置您感兴趣的部分.
  2. 在代码中使用Python libnl来复制它.

(请注意,libnl/netlink被设计为一种非常通用的,长期可扩展的机制.它实际上是为了取代ad-hoc ioctl而设计的.这种通用性带来了一定的复杂性:它可能非常复杂/涉及大量编码,甚至可以完成简单的任务.)

正如我上面写的那样,用自己的代码来替换工具可能是一项相当艰巨的任务.grep'ing命令的输出是几分钟的代码,而这里可能是几天或几周的工作.所以你必须在"快速而简单但不那么干净"和"自足,清洁,可扩展但昂贵"之间做出选择.这取决于:你是否致力于生产工业级的,客户支持的软件,它是一个内部公司工具,还是一个周末的业余爱好软件项目.