كيف يمكنني تحديد كافة عناوين IP الخاصة بي عندما يكون لدي بطاقات NIC متعددة؟
-
06-07-2019 - |
سؤال
لدي عدة بطاقات واجهة شبكة على جهاز الكمبيوتر الخاص بي، ولكل منها عنوان IP الخاص بها.
عندما أستخدم gethostbyname(gethostname())
من بايثون (مدمج) socket
الوحدة، وسوف يعود واحد منهم فقط.كيف أحصل على الآخرين؟
المحلول
واستخدم 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
القوائم والقواميس في كل مكان، انها لجهاز كمبيوتر واحد يمكن أن يكون الآخذة متعددة، ولكل NIC يمكن أن يكون لها عناوين متعددة، ولكل عنوان لديها مجموعة من الخيارات.
نصائح أخرى
import socket
[i[4][0] for i in socket.getaddrinfo(socket.gethostname(), None)]
جميع العناوين في سطر واحد مع مساعدة من وحدة netifaces
:
[netifaces.ifaddresses(iface)[netifaces.AF_INET][0]['addr'] for iface in netifaces.interfaces() if netifaces.AF_INET in netifaces.ifaddresses(iface)]
فقط من أجل الاكتمال، سيكون هناك خيار آخر هو الاستخدام psutil.
تلدر؛
import socket
import psutil
def get_ip_addresses(family):
for interface, snics in psutil.net_if_addrs().items():
for snic in snics:
if snic.family == family:
yield (interface, snic.address)
ipv4s = list(get_ip_addresses(socket.AF_INET))
ipv6s = list(get_ip_addresses(socket.AF_INET6))
توضيح
الوظيفة التي تحتاجها هي net_if_addrs
.أي.:
import psutil
psutil.net_if_addrs()
مما يؤدي إلى شيء مثل هذا (Python 3):
{'br-ae4880aa80cf': [snic(family=<AddressFamily.AF_INET: 2>, address='172.18.0.1', netmask='255.255.0.0', broadcast='172.18.0.1', ptp=None),
snic(family=<AddressFamily.AF_PACKET: 17>, address='02:42:e5:ae:39:94', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)],
'docker0': [snic(family=<AddressFamily.AF_INET: 2>, address='172.17.0.1', netmask='255.255.0.0', broadcast='172.17.0.1', ptp=None),
snic(family=<AddressFamily.AF_PACKET: 17>, address='02:42:38:d2:4d:77', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)],
'eno1': [snic(family=<AddressFamily.AF_PACKET: 17>, address='54:be:f7:0b:cf:a9', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)],
'lo': [snic(family=<AddressFamily.AF_INET: 2>, address='127.0.0.1', netmask='255.0.0.0', broadcast=None, ptp=None),
snic(family=<AddressFamily.AF_PACKET: 17>, address='00:00:00:00:00:00', netmask=None, broadcast=None, ptp=None)],
'wlp2s0': [snic(family=<AddressFamily.AF_INET: 2>, address='192.168.1.4', netmask='255.255.255.0', broadcast='192.168.1.255', ptp=None),
snic(family=<AddressFamily.AF_PACKET: 17>, address='00:21:27:ee:d6:03', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)]}
(بيثون 2):
{'br-ae4880aa80cf': [snic(family=2, address='172.18.0.1', netmask='255.255.0.0', broadcast='172.18.0.1', ptp=None),
snic(family=17, address='02:42:e5:ae:39:94', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)],
'docker0': [snic(family=2, address='172.17.0.1', netmask='255.255.0.0', broadcast='172.17.0.1', ptp=None),
snic(family=17, address='02:42:38:d2:4d:77', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)],
'eno1': [snic(family=17, address='54:be:f7:0b:cf:a9', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)],
'lo': [snic(family=2, address='127.0.0.1', netmask='255.0.0.0', broadcast=None, ptp=None),
snic(family=17, address='00:00:00:00:00:00', netmask=None, broadcast=None, ptp=None)],
'wlp2s0': [snic(family=2, address='192.168.1.4', netmask='255.255.255.0', broadcast='192.168.1.255', ptp=None),
snic(family=17, address='00:21:27:ee:d6:03', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)]}
ملحوظة:نظرًا لأنه يمكن أن يكون لديك أكثر من عنوان واحد من نفس العائلة مرتبطًا بكل واجهة، فإن قيم الإملاء هي قوائم.
كل snic
هو namedtuple
والذي يتضمن 5 مجالات:
family
:عائلة العناوين، إما AF_INET أو AF_INET6 أو psutil.AF_LINK، والتي تشير إلى عنوان MAC.address
:عنوان NIC الأساسي (المضبوط دائمًا).netmask
:عنوان قناع الشبكة (قد يكون لا شيء).broadcast
:عنوان البث (قد يكون لا شيء).ptp
:تعني "نقطة إلى نقطة"؛إنه عنوان الوجهة على واجهة نقطة إلى نقطة (عادةً VPN).البث وptp متنافيان (قد لا يكونا).
https://docs.python.org/3.4/library/socket.html#socket.if_nameindex
المقبس.if_nameindex()
قم بإرجاع قائمة بمعلومات واجهة الشبكة (الفهرس، سلسلة الاسم) من الصفوف.خطأ OSE في حالة فشل استدعاء النظام.
التوفر:يونكس.
الجديد في الإصدار 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')]
وانها لينكس فقط، ولكن هناك وصفة بسيطة جدا هنا http://code.activestate.com / وصفات / 439094 /
وربما يستخدم رمز مشابهة لما netifaces حزمة المذكورة في إجابة أخرى (ولكن التيار إصدار مرتبطة هنا)
ووsocket.getaddrinfo () لا فعلا إرجاع عنوان IP منضم للجهاز. إذا احتوى ملف المضيفين خط مع "127.0.1.1 yourhost.example.com yourhost"، وهو تكوين المشترك، getaddrinfo في لن يؤدي الا الى العودة 127.0.1.1.
وهنا هو روتين للعثور على جميع الواجهات IPv4 و IPv6. كما أشار ملصق سابقة بها، socket.gethostbyname_ex () لا يعمل ل IPv6، ويوصي وثائق بيثون واحد استخدام <لأ href = "http://docs.python.org/library/socket.html#socket.getaddrinfo" يختلط = "نوفولو noreferrer"> socket.getaddressinfo () بدلا من ذلك.
وهذا الروتين يضيف واجهة رد عناوين IPv4 (127.0.0.1)، وإذا كان هناك أي واجهات الإصدار IPv6 ثم فإنه يضيف أيضا ب IPv6 واجهة رد (:: 1). على الجهاز الخاص بي، socket.getaddrinfo () سوف تعطيني واحد أو كل من هذه ولكن فقط إذا ليس لدي أي واجهات الأخرى المتاحة.
لاحتياجات بلدي، كنت أرغب في محاولة لفتح مأخذ توصيل UDP على منفذ محدد على كل من بلدي واجهات المتاحة، وهذا هو السبب رمز له "الميناء" و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]
ويجب عليك الحصول على مباشرة كافة عناوين IP تكوين IP، على سبيل المثال عن طريق تشغيل إفكونفيغ وتحليل انتاجها (أنه من الممكن أيضا أن تفعل ما يفعل إفكونفيغ مباشرة في بيثون أ >، نرى كيف يتم ذلك في C ). إذا كنت تريد أسماء المضيفين، واستخدام gethostbyaddr.
وأعتقد أن الجوابHarley هولكومب هي قابلة للتطبيق، ولكن إذا كان لديك بعض بطاقات NIC الظاهري دون الملكية الفكرية سيكون خطأ. لذلك هذا هو ط تعديل:
def get_lan_ip():
for interface in interfaces():
try:
for link in ifaddresses(interface)[AF_INET]:
if str(link['addr']).startswith("172."):
return str(link['addr'])
except:
pass
وهذا سيعود فقط شبكة الاتصال المحلية من IPv4
وكما يشير هذا الموضوع، وهناك الكثير من الطرق لacchive نفس النتيجة، في طريقي المقترح هو للاستفادة من البناء في الأسرة مرشح في getaddrinfo()
وتحليل الصفوف (tuple) موحدة مثل ذلك:
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