如何僅使用標準庫在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地址可能比此處列出的任何方法都更可靠和可靠。