如何仅使用标准库在Python平台中独立查找本地IP地址(即192.168.xx或10.0.xx)? python
我不得不解决“找出IP地址是否在本地”这一问题,个人第一个想法是创建一个本地IP地址列表,而后与之匹配。 这就是致使我提出这个问题的缘由。 可是,我后来意识到有一种更直接的方法:尝试在该IP上绑定并查看它是否有效。 linux
_local_ip_cache = [] _nonlocal_ip_cache = [] def ip_islocal(ip): if ip in _local_ip_cache: return True if ip in _nonlocal_ip_cache: return False s = socket.socket() try: try: s.bind((ip, 0)) except socket.error, e: if e.args[0] == errno.EADDRNOTAVAIL: _nonlocal_ip_cache.append(ip) return False else: raise finally: s.close() _local_ip_cache.append(ip) return True
我知道这并不能直接回答问题,可是这对尝试解决相关问题的任何人以及遵循相同思路的人都应该有所帮助。 这具备做为跨平台解决方案的优点(我认为)。 服务器
这将适用于大多数linux系统: 网络
import socket, subprocess, re def get_ipv4_address(): """ Returns IP address(es) of current machine. :return: """ p = subprocess.Popen(["ifconfig"], stdout=subprocess.PIPE) ifc_resp = p.communicate() patt = re.compile(r'inet\s*\w*\S*:\s*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})') resp = patt.findall(ifc_resp[0]) print resp get_ipv4_address()
使用IP命令并返回IPv4和IPv6地址的命令版本略有改进: app
import commands,re,socket #A generator that returns stripped lines of output from "ip address show" iplines=(line.strip() for line in commands.getoutput("ip address show").split('\n')) #Turn that into a list of IPv4 and IPv6 address/mask strings addresses1=reduce(lambda a,v:a+v,(re.findall(r"inet ([\d.]+/\d+)",line)+re.findall(r"inet6 ([\:\da-f]+/\d+)",line) for line in iplines)) #addresses1 now looks like ['127.0.0.1/8', '::1/128', '10.160.114.60/23', 'fe80::1031:3fff:fe00:6dce/64'] #Get a list of IPv4 addresses as (IPstring,subnetsize) tuples ipv4s=[(ip,int(subnet)) for ip,subnet in (addr.split('/') for addr in addresses1 if '.' in addr)] #ipv4s now looks like [('127.0.0.1', 8), ('10.160.114.60', 23)] #Get IPv6 addresses ipv6s=[(ip,int(subnet)) for ip,subnet in (addr.split('/') for addr in addresses1 if ':' in addr)]
这个答案是我我的尝试解决的问题,由于socket.gethostbyname(socket.gethostname())
也返回了127.0.0.1。 此方法不须要Internet,仅须要LAN链接便可。 代码适用于Python 3.x,但能够轻松转换为2.x。 使用UDP广播: socket
import select import socket import threading from queue import Queue, Empty def get_local_ip(): def udp_listening_server(): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.bind(('<broadcast>', 8888)) s.setblocking(0) while True: result = select.select([s],[],[]) msg, address = result[0][0].recvfrom(1024) msg = str(msg, 'UTF-8') if msg == 'What is my LAN IP address?': break queue.put(address) queue = Queue() thread = threading.Thread(target=udp_listening_server) thread.queue = queue thread.start() s2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s2.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) waiting = True while waiting: s2.sendto(bytes('What is my LAN IP address?', 'UTF-8'), ('<broadcast>', 8888)) try: address = queue.get(False) except Empty: pass else: waiting = False return address[0] if __name__ == '__main__': print(get_local_ip())
做为名为myip
的别名,该别名应可在任何地方使用: ide
alias myip="python -c 'import socket; print([l for l in ([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith(\"127.\")][:1], [[(s.connect((\"8.8.8.8\", 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) if l][0][0])'"
与上述相同,但只有Python代码: spa
import socket print([l for l in ([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][:1], [[(s.connect(('8.8.8.8', 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) if l][0][0])
在没有Internet链接的状况下也能够在LAN上运行的版本: code
import socket print((([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")] or [[(s.connect(("8.8.8.8", 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) + ["no IP found"])[0])
(感谢@ccpizza ) server
背景 :
使用socket.gethostbyname(socket.gethostname())
在这里不起做用,由于我所在的其中一台计算机上的/etc/hosts
具备重复的条目和对其自身的引用。 socket.gethostbyname()
仅返回/etc/hosts
的最后一个条目。
这是我最初的尝试,清除了全部以"127."
开头的地址。 :
import socket print([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][:1])
这适用于Linux 2和Windows上的Python 2和3,但不适用于多个网络设备或IPv6。 可是,它中止了在最近的Linux发行版上的工做,所以我尝试了这种替代技术。 它尝试经过端口53
在8.8.8.8
链接到Google DNS服务器:
import socket print([(s.connect(('8.8.8.8', 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1])
而后,我将上述两种技术组合成一个单行代码,该代码行应可在任何地方使用,并在此答案的顶部建立了myip
别名和Python代码段。
随着IPv6的日益普及以及对于具备多个网络接口的服务器,使用第三方Python模块查找IP地址可能比此处列出的任何方法都更可靠和可靠。