コンピューターに複数のネットワーク インターフェイス カードがあり、それぞれに独自の IP アドレスがあります。
gethostbyname(gethostname())
Python の (組み込み)socket
モジュールから使用すると、そのうちの 1 つだけが返されます。他はどうやって手に入れるの?
コンピューターに複数のネットワーク インターフェイス カードがあり、それぞれに独自の IP アドレスがあります。
gethostbyname(gethostname())
Python の (組み込み)socket
モジュールから使用すると、そのうちの 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_INET6
代わりに を使用しAF_INET
ます。がリストや辞書を至る所で使用する理由が気になる場合はnetifaces
、1 台のコンピューターが複数の NIC を持つことができ、各 NIC が複数のアドレスを持つことができ、各アドレスに独自のオプション セットがあるためです。
https://docs.python.org/3.4/library/socket.html#socket.if_nameindex
socket.if_nameindex()
ネットワーク インターフェイス情報 (インデックス int、名前文字列) タプルのリストを返します。システムコールが失敗した場合は OSError。
可用性: Unix。
バージョン 3.3 の新機能。
Python 3.4、UNIX / Linuxで実行可能なこのコードを作成しました
#!/env/python3.4
import socket
import fcntl
import struct
def active_nic_addresses():
"""
Return a list of IPv4 addresses that are active on the computer.
"""
addresses = [ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][:1]
return addresses
def get_ip_address( NICname ):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
return socket.inet_ntoa(fcntl.ioctl(
s.fileno(),
0x8915, # SIOCGIFADDR
struct.pack('256s', NICname[:15].encode("UTF-8"))
)[20:24])
def nic_info():
"""
Return a list with tuples containing NIC and IPv4
"""
nic = []
for ix in socket.if_nameindex():
name = ix[1]
ip = get_ip_address( name )
nic.append( (name, ip) )
return nic
if __name__ == "__main__":
print( active_nic_addresses() )
print( nic_info() )
次のようなものが出力されます。
['192.168.0.2']
[('lo', '127.0.0.1'), ('enp3s0', '192.168.0.2')]
このスレッドが示すように、同じ結果を得るには多くの方法があります。私の提案する方法は、組み込みのファミリ フィルターを活用してgetaddrinfo()
、標準化されたタプルを次のように解析することです。
from socket import getaddrinfo, AF_INET, gethostname
for ip in getaddrinfo(host=gethostname(), port=None, family=AF_INET):
print(ip[4][0])
出力例:
192.168.55.1
192.168.170.234
Linuxのみですが、ここに非常に簡単なレシピがありますhttp://code.activestate.com/recipes/439094/
おそらく別の回答で言及されているnetifacesパッケージと同様のコードを使用しています(ただし、現在のバージョンはここにリンクされています)
socket.getaddrinfo()は、実際にはデバイスのバインドされたIPアドレスを返しません。ホストファイルに「127.0.1.1yourhost.example.comyourhost」という一般的な構成の行が含まれている場合、getaddrinfoは127.0.1.1のみを返します。
これは、すべてのIPv4およびIPv6インターフェースを見つけるためのルーチンです。以前の投稿者が指摘したように、socket.gethostbyname_ex()はIPv6では機能せず、Pythonのドキュメントでは代わりにsocket.getaddressinfo()を使用することを推奨しています。
このルーチンは、コールバックIPv4インターフェース(127.0.0.1)を追加し、IPv6インターフェースがある場合は、コールバックIPv6インターフェース(:: 1)も追加します。私のマシンでは、socket.getaddrinfo()はこれらの一方または両方を提供しますが、他に使用可能なインターフェースがない場合に限ります。
必要に応じて、使用可能な各インターフェイスの指定されたポートでUDPソケットを開こうとしました。そのため、コードには「port」とsocket.SOCK_DGRAMが含まれています。たとえば、ポートを念頭に置いていない場合は、これらを変更しても安全です。
addrinfo_ipv4 = socket.getaddrinfo(hostname,port,socket.AF_INET,socket.SOCK_DGRAM)
addrinfo_ipv6 = []
try:
addrinfo_ipv6 = socket.getaddrinfo(hostname,port,socket.AF_INET6,socket.SOCK_DGRAM)
except socket.gaierror:
pass
addrinfo = [(f,t,a) for f,t,p,cn,a in addrinfo_ipv4+addrinfo_ipv6]
addrinfo_local = [(socket.AF_INET,socket.SOCK_DGRAM,('127.0.0.1',port))]
if addrinfo_ipv6:
addrinfo_local.append( (socket.AF_INET6,socket.SOCK_DGRAM,('::1',port)) )
[addrinfo.append(ai) for ai in addrinfo_local if ai not in addrinfo]
このスニペットは、システムで使用可能なすべての IPV4 アドレスのリストを提供します。
import itertools
from netifaces import interfaces, ifaddresses, AF_INET
links = filter(None, (ifaddresses(x).get(AF_INET) for x in interfaces()))
links = itertools.chain(*links)
ip_addresses = [x['addr'] for x in links]
たとえば、 ifconfig を実行してその出力を解析することにより、すべての IP 構成済み IP アドレスを直接取得する必要があります ( ifconfig が行うことを Pythonで直接行うこともできます。 C で行う方法を参照してください)。ホスト名が必要な場合は、gethostbyaddr を使用します。
次のようにかなり簡単に実行できます。
import netifaces
for interface in netifaces.interfaces():
print netifaces.ifaddresses(interface)
詳細については、netifaces のドキュメントを参照してください。