gethostbyaddr(gethostname())がIPv6 IPを返すのはなぜですか?
-
03-07-2019 - |
質問
Pythonを使用して簡単なサーバーアプリケーションを作成する作業を行っており、リスニングソケットをバインドするIPを取得しようとしています。私が見た例ではこれを使用しています:
HOST = gethostbyaddr(gethostname())
この後、もう少し処理すると、文字列としてホストIPのみが表示されます。これにより、IPv4アドレスが返されます。しかし、このコードを実行すると、IPv6アドレスが返されます。なぜこれを行うのですか?IPv4アドレスを取得するにはどうすればよいですか
関連する場合は、Windows VistaとPython 2.5を使用しています
解決
IPアドレスを取得するのは、思っているより難しいです。
チェックこの回答私が見つけた信頼できる方法の1つに挙げました。
クリックしたくない場合の答えは次のとおりです。
netifaces
モジュールを使用します。ネットワークは複雑であるため、netifacesを使用するのは少し難しい場合がありますが、ここでは必要なことを行う方法を示します。
>>> import netifaces
>>> netifaces.interfaces()
['lo', 'eth0']
>>> netifaces.ifaddresses('eth0')
{17: [{'broadcast': 'ff:ff:ff:ff:ff:ff', 'addr': '00:11:2f:32:63:45'}], 2: [{'broadcast': '10.0.0.255', 'netmask': '255.255.255.0', 'addr': '10.0.0.2'}], 10: [{'netmask': 'ffff:ffff:ffff:ffff::', 'addr': 'fe80::211:2fff:fe32:6345%eth0'}]}
>>> for interface in netifaces.interfaces():
... print netifaces.ifaddresses(interface)[netifaces.AF_INET]
...
[{'peer': '127.0.0.1', 'netmask': '255.0.0.0', 'addr': '127.0.0.1'}]
[{'broadcast': '10.0.0.255', 'netmask': '255.255.255.0', 'addr': '10.0.0.2'}]
>>> for interface in netifaces.interfaces():
... for link in netifaces.ifaddresses(interface)[netifaces.AF_INET]:
... print link['addr']
...
127.0.0.1
10.0.0.2
これは、次のようにもう少し読みやすくすることができます:
from netifaces import interfaces, ifaddresses, AF_INET
def ip4_addresses():
ip_list = []
for interface in interfaces():
for link in ifaddresses(interface)[AF_INET]:
ip_list.append(link['addr'])
return ip_list
IPv6アドレスが必要な場合は、 AF_INET
ではなく AF_INET6
を使用します。 netifaces
があちこちでリストと辞書を使用する理由を知りたい場合は、単一のコンピューターに複数のNICがあり、各NICに複数のアドレスがあり、各アドレスに独自のオプションセットがあるためです。
他のヒント
IPv6はより新しいファミリであるため、IPv4よりも優先されます。ホスト名が複数のファミリに関連付けられている場合、通常はIPv6が必要です。家族に依存しない解決には getaddrinfo を使用する必要があります。ここに例を示します。
import sys, socket;
host = socket.gethostname();
result = socket.getaddrinfo(host, None);
print "family:%i socktype:%i proto:%i canonname:%s sockaddr:%s"%result[0];
result = socket.getaddrinfo(host, None, socket.AF_INET);
print "family:%i socktype:%i proto:%i canonname:%s sockaddr:%s"%result[0];
result = socket.getaddrinfo(host, None, socket.AF_INET6);
print "family:%i socktype:%i proto:%i canonname:%s sockaddr:%s"%result[0];
デュアルスタック構成のホストでは、次のようになります
family:10 socktype:1 proto:6 canonname: sockaddr:('2002:dce8:d28e::31', 0, 0, 0)
family:2 socktype:1 proto:6 canonname: sockaddr:('10.6.28.31', 0)
family:10 socktype:1 proto:6 canonname: sockaddr:('2002:dce8:d28e::31', 0, 0, 0)
gethostbyaddr()
はホスト名ではなく、パラメータとしてのIPアドレスです。したがって、例外をスローすることなくまったく機能していることに驚いています。代わりに gethostbyname()
を意味する場合、その機能はIPv6をサポートしていないと主張しているため、結果はさらに驚くべきものになります。 ハーレーの回答では、IPアドレスを正しく取得する方法について説明しています。