我的目标是从 Windows 计算机发现本地网络中 Linux 计算机“服务器”的 IP 地址。从另一台 Linux 计算机“客户端”我可以这样做:
ping -c1 server.local
并得到回复。 “服务器”和“客户端”都运行 Avahi,所以这很容易。但是,我想从我的 Python 应用程序中发现“服务器”的 IP 地址,该应用程序在 MS Windows 和 Linux 计算机上运行。注意:在 未 运行 mDNS 软件的 MS Windows 计算机上,没有主机名解析(显然 ping
在所述 Windows 系统上不起作用)。
我知道 pyzeroconf 的存在,这是我尝试使用的模块;但是,文档很少,对我帮助不大。使用像 avahi-discover
这样的工具,我发现计算机发布了 mDNS 类型的服务类型 _workstation._tcp.local.
(带有明显的虚拟端口 9,丢弃服务)的记录 PTR
这可能相当于 DNS A 记录。或者我可能完全误解了 mDNS 机制。
如何通过 Python 的 mDNS 发现计算机的 IP 地址(或获取计算机的 IP 地址列表)?
澄清(基于评论)
显而易见的 socket.gethostbyname
在运行并配置为使用 mDNS 软件(如 Avahi)的计算机上工作:
Python 2.6.5 (r265:79063, Apr 16 2010, 13:09:56)
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import socket
>>> socket.gethostbyname('server.local')
'192.168.42.42'
但是,在未运行 mDNS 软件(默认)的 Windows 计算机上,我得到:
Python 2.7.1 (r271:86832, Nov 27 2010, 18:30:46) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import socket
>>> socket.gethostbyname('server.local')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
socket.gaierror: [Errno 11001] getaddrinfo failed
原文由 tzot 发布,翻译遵循 CC BY-SA 4.0 许可协议
如果有人对此仍然感兴趣,可以在 Windows 和 Linux 上使用 dnspython 完成任务,如下所示:
此代码在目标计算机运行 avahi 时有效,但在目标运行 python zeroconf 或 esp8266 mdns 实现时 失败。有趣的是,运行 avahi 的 Linux 系统成功地解决了这些目标(avahi 显然实现了 nssswitch.conf mdns 插件并且是 mdns 协议的更完整实现)
如果是天真的 mdns 响应器,它与 rfc 相反,通过 mdns 端口发送响应,以下代码(在 linux 和 windows 上运行并解析 linux avahi、hp 打印机和 esp8266 目标)对我有用:(并且也是 不兼容,因为它使用 MDNS 端口发送查询,而它显然 不是 完整的实现)
通过向构造函数传递从网络收集的字符串,在上面的代码中创建了空的 dns 对象
此查询由 nslookup 生成,因此其 id 为非零(在本例中为 \xf6\xe8)试图解析 esp01.local。然后通过以下方式创建包含空查询的 dns 对象:
同样的结果也可以通过以下方式创建:
也可以使用非空查询创建 dns 对象:
甚至有多个查询:
但最少的响应者可能无法处理包含多个查询的 dns 消息
我也不满意 python zeroconf 文档。从随意阅读代码和使用 tcpdump 的数据包监控来看,似乎(当注册示例运行时)zeroconf 将响应地址查询,但 nslookup 忽略(或不接收)答案。