为什么 pyro4 无法在 127.0.1.1 下定位名称服务器但在 127.0.0.1 下成功?

Why does pyro4 fail to locate nameserver under 127.0.1.1 but succeed with 127.0.0.1?

我正在尝试 运行 带有自定义事件循环的 pyro4 服务器 Raspberry Pi 运行ning Raspbian 8 (jessie)。当我使用从 socket.gethostname() 获得的主机名创建名称服务器时,特别是 'raspberrypi',我的客户端脚本找不到名称服务器。当我使用 'localhost' 作为主机名时,我的客户端脚本能够找到主机名。在/etc/hosts中,'raspberrypi'绑定到127.0.1.1,而'localhost'显然绑定到127.0.0.1。我原以为这两个地址都绑定到环回接口,所以我不明白为什么一个应该工作而另一个不工作。

对于它的价值,在对 pyro4 代码进行一些挖掘之后,它看起来像 Pyro4.naming.py 的 l.463,对 proxy.ping() 的调用失败了 127.0.1.1 但不是127.0.0.1,这最终是触发前一个地址失败的原因。不是 Pyro 的专家,不清楚这种行为是否是预期的。有什么想法吗?我认为这一定是一个常见问题,因为大多数(所有?)Debian 版本在 /etc/hosts 中为这两个地址包含单独的行。

我在下面附上了重现问题的代码。这基本上只是 pyro 附带的 "eventloop" 示例的略微修改版本。

server.py:

import socket
import select
import sys
import Pyro4.core
import Pyro4.naming

import MotorControl

Pyro4.config.SERVERTYPE="thread"
hostname=socket.gethostname()

print("initializing services... servertype=%s" % Pyro4.config.SERVERTYPE)
# start a name server with broadcast server as well
nameserverUri, nameserverDaemon, broadcastServer = Pyro4.naming.startNS(host=hostname)
pyrodaemon=Pyro4.core.Daemon(host=hostname)

motorcontroller = MotorControl.MotorControl()
serveruri=pyrodaemon.register(motorcontroller)
nameserverDaemon.nameserver.register("example.embedded.server",serveruri)

# below is our custom event loop.
while True:
    nameserverSockets = set(nameserverDaemon.sockets)
    pyroSockets = set(pyrodaemon.sockets)
    rs = []
    rs.extend(nameserverSockets)
    rs.extend(pyroSockets)

    rs,_,_ = select.select(rs,[],[], 0.001)

    eventsForNameserver=[]
    eventsForDaemon=[]
    for s in rs:
        if s in nameserverSockets:
            eventsForNameserver.append(s)
        elif s in pyroSockets:
            eventsForDaemon.append(s)
    if eventsForNameserver:
        nameserverDaemon.events(eventsForNameserver)
    if eventsForDaemon:
        pyrodaemon.events(eventsForDaemon)

    motorcontroller.increment_count()

nameserverDaemon.close()
broadcastServer.close()
pyrodaemon.close()

client.py:

from __future__ import print_function
import Pyro4

proxy=Pyro4.core.Proxy("PYRONAME:example.embedded.server")
print("count = %d" % proxy.get_count())

MotorControl.py

class MotorControl(object):
    def __init__(self):
        self.switches = 0

    def get_count(self):
        return self.switches

    def increment_count(self):
        self.switches = self.switches + 1

错误:

Traceback (most recent call last):
  File "pyroclient.py", line 5, in <module>
    print("count = %d" % proxy.get_count())
  File "/usr/local/lib/python2.7/dist-packages/Pyro4/core.py", line 248, in __getattr__
    self._pyroGetMetadata()
  File "/usr/local/lib/python2.7/dist-packages/Pyro4/core.py", line 548, in _pyroGetMetadata
    self.__pyroCreateConnection()
  File "/usr/local/lib/python2.7/dist-packages/Pyro4/core.py", line 456, in __pyroCreateConnection
    uri = resolve(self._pyroUri, self._pyroHmacKey)
  File "/usr/local/lib/python2.7/dist-packages/Pyro4/naming.py", line 548, in resolve
    nameserver = locateNS(uri.host, uri.port, hmac_key=hmac_key)
  File "/usr/local/lib/python2.7/dist-packages/Pyro4/naming.py", line 528, in locateNS
    raise e
Pyro4.errors.NamingError: Failed to locate the nameserver

Pyro 的名称服务器查找依赖于两件事:

  • 广播查找
  • 直接查找 hostname/ip-address

当您使用环回适配器绑定名称服务器时,第一个不可用(环回不支持广播套接字)。所以我们只剩下第二个了。 您的问题的答案很简单:直接查找是根据 NS_HOST 配置项的值完成的,默认设置为 'localhost'。由于本地主机解析为 127.0.0.1,因此它永远不会连接到 127.0.1.1。

建议:在 0.0.0.0 或“”(空主机名)上绑定名称服务器,它也应该能够启动广播响应程序。这样您的客户就不会遇到任何问题。

或者,只需为您的客户将 NS_HOST 设置为 127.0.1.1(或您机器的主机名),如果名称服务器绑定在 127.0.1.1