获取 Twisted 服务器的 IP 地址

Get Twisted server's IP address

如果我有一个 Twisted 服务器,我怎样才能找到它的 public-facing IP 地址?

以这个简单的回显服务器为例:

from twisted.internet import protocol, reactor, endpoints

class Echo(protocol.Protocol):
    def dataReceived(self, data):
        self.transport.write(data)

class EchoFactory(protocol.Factory):
    def buildProtocol(self, addr):
        return Echo()

server_endpoint = endpoints.serverFromString(reactor, "tcp:1234")
listening_port_deferred = server_endpoint.listen(EchoFactory())
reactor.run()

我期待 server_endpoint.getHost(),但我看不到 TCP4ServerEndpoint 提供任何有用的东西。

通过在reactor.run()之前添加以下行,我们可以看到服务器正在监听所有接口(0.0.0.0):

def print_host(listening_port):
    print("listening_port.getHost():", listening_port.getHost())
listening_port_deferred.addCallback(print_host)

输出listening_port.getHost(): IPv4Address(type='TCP', host='0.0.0.0', port=1234)。但这对我们获取服务器网络接口的 IP 地址没有帮助。

我们可以通过在buildProtocol():

的第一行添加以下内容来获取客户端的IP地址
print("Client's address:", addr.host)

但这只给了我们客户的地址。

我应该如何获取服务器的 IP 地址?

Twisted 会告诉您绑定服务器的地址,只使用您在侦听端口上找到的方法 getHost。不幸的是,您发现它有很大的局限性,即当服务器侦听所有本地地址 (INADDR_ANY) 时,它会为您提供 0.0.0.0([=12= 的规范 IPv4 点分四边形表示) ]).

发生这种情况时,您必须离开 Twisted。我发现 netifaces 包对此非常有用。来自文档:

>>> netifaces.interfaces()
['lo0', 'gif0', 'stf0', 'en0', 'en1', 'fw0']
>>> >>> addrs = netifaces.ifaddresses('lo0')
>>> addrs[netifaces.AF_INET]
[{'peer': '127.0.0.1', 'netmask': '255.0.0.0', 'addr': '127.0.0.1'}]

通过将此信息与 0.0.0.0 表示“所有本地地址”的观察相结合,您可以计算出服务器将接受哪些本地地址的连接。

感谢 notorious 的评论,我意识到服务器的 IP 地址只有在客户端连接后才可用。然而,正如 Jean-Paul 指出的那样,这个 IP 地址不一定是面向 public 的,很可能位于 NATing 路由器之后。

要获取给定连接的服务器 IP 地址,我们可以使用 Protocol class. This is documented in the ITransport 接口的 transport 属性中的 getHost() 方法。

比如我们在原题的Echo协议class中加入如下方法,每次客户端连接时,服务器端都会打印出使用过的IP地址。

def connectionMade(self):
    print("IP address of host given connection:", self.transport.getHost())

因此,例如,如果您从服务器 运行 所在的同一台计算机连接,您将看到:

IP address of host given connection: IPv4Address(type='TCP', host='127.0.0.1', port=1234)

但是,如果您从同一网络上的另一台计算机连接,您可能会看到:

IP address of host given connection: IPv4Address(type='TCP', host='192.168.5.103', port=1234)