Finding local IP addresses using Python's stdlib
如何在Python平台中独立地找到本地IP地址(即192.168.x.x或10.0.x.x)并仅使用标准库?
我刚刚发现了这个,但它似乎有点hackish,但是他们说在* nix上尝试了它,我在Windows上做了它并且它有效。
1 2 3 4 5 | import socket s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(("8.8.8.8", 80)) print(s.getsockname()[0]) s.close() |
这假设您具有Internet访问权限,并且没有本地代理。
1 2 | import socket socket.gethostbyname(socket.gethostname()) |
这总是不起作用(在
此方法返回本地框(具有默认路由的IP)上的"主"IP。
- 不需要可路由的网络访问或任何连接。
- 即使从网络上拔下所有接口,也能正常工作。
- 不需要甚至尝试去其他任何地方。
- 适用于NAT,公共,私有,外部和内部IP
- 纯Python 2(或3)没有外部依赖。
- 适用于Linux,Windows和OSX。
Python 2或3:
1 2 3 4 5 6 7 8 9 10 11 12 | import socket def get_ip(): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: # doesn't even have to be reachable s.connect(('10.255.255.255', 1)) IP = s.getsockname()[0] except: IP = '127.0.0.1' finally: s.close() return IP |
这将返回一个主要的IP(具有默认路由的IP)。如果您需要将所有IP连接到所有接口(包括localhost等),请参阅此答案。
如果你在家里的wifi防火墙之后就像NAT防火墙一样,那么这将不会显示你的公共NAT IP,而是显示本地网络上的私有NAT IP,它具有到本地WIFI路由器的默认路由;获取你的无线路由器的外部IP要么需要在这个盒子上运行,要么连接到可以反映IP的外部服务,例如whatismyip.com/whatismyipaddress.com ......但这与原始问题完全不同。 :)
在评论中根据Pedro的建议更新了connect()调用。 (如果您需要特定的许可声明,这是公共域/免费用于任何用途,或者根据您的选择每个Stack Overflow的代码/内容许可证的MIT / CC2-BY-SA。)
作为一个名为
1 | 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 2.x,Python 3.x,现代和旧版Linux发行版,OSX / macOS和Windows,用于查找当前的IPv4地址。
- 对于具有多个IP地址,IPv6,未配置IP地址或无法访问Internet的计算机,将无法返回正确的结果。
与上面相同,但只有Python代码:
1 2 | 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]) |
- 如果未配置IP地址,则会引发异常。
在没有互联网连接的LAN上也可以使用的版本:
1 2 | 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)
背景:
使用
这是我最初的尝试,它清除了以
1 2 | import socket print([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][:1]) |
这适用于Linux和Windows上的Python 2和3,但不涉及多个网络设备或IPv6。但是,它停止了最近的Linux发行版,所以我尝试了这种替代技术。它尝试在端口
1 2 | 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]) |
然后我将上述两种技术组合成一个应该可以在任何地方工作的单行程,并在此答案的顶部创建了
随着IPv6的日益普及,以及具有多个网络接口的服务器,使用第三方Python模块查找IP地址可能比此处列出的任何方法都更强大和可靠。
您可以使用netifaces模块。只需输入:
1 | pip install netifaces |
在命令shell中,它将自己安装在默认的Python安装上。
然后你可以像这样使用它:
1 2 3 4 | from netifaces import interfaces, ifaddresses, AF_INET for ifaceName in interfaces(): addresses = [i['addr'] for i in ifaddresses(ifaceName).setdefault(AF_INET, [{'addr':'No IP addr'}] )] print '%s: %s' % (ifaceName, ', '.join(addresses)) |
在我的电脑上打印:
1 2 | {45639BDC-1050-46E0-9BE9-075C30DE1FBC}: 192.168.0.100 {D43A468B-F3AE-4BF9-9391-4863A4500583}: 10.5.9.207 |
该模块的作者声称它应该适用于Windows,UNIX和Mac OS X.
套接字API方法
请参阅https://stackoverflow.com/a/28950776/711085
缺点:
- 不是跨平台的。
- 需要更多的后备代码,与互联网上特定地址的存在相关联
- 如果你在NAT后面,这也行不通
- 可能创建UDP连接,而不是独立于(通常是ISP)的DNS可用性(请参阅其他答案,例如使用8.8.8.8:Google(巧合的是DNS)服务器)
- 确保将目标地址设置为UNREACHABLE,例如规格保证未使用的数字IP地址。请勿使用fakesubdomain.google.com或somefakewebsite.com等域名;您仍然会在该方(现在或将来)发送垃圾邮件,并在此过程中向您自己的网络框发送垃圾邮件。
反射器方法
(请注意,这不符合OP的本地IP地址问题,例如192.168 ......;它会为您提供公共IP地址,根据用例情况,这可能更合适。)
您可以查询某些网站,例如whatismyip.com(但使用API??),例如:
1 2 3 4 5 6 7 8 9 | from urllib.request import urlopen import re def getPublicIp(): data = str(urlopen('http://checkip.dyndns.com/').read()) # data = '<html><head>Current IP Check</head><body>Current IP Address: 65.96.168.198</body></html> ' return re.compile(r'Address: (\d+\.\d+\.\d+\.\d+)').search(data).group(1) |
或者如果使用python2:
1 2 3 4 5 6 7 8 9 | from urllib import urlopen import re def getPublicIp(): data = str(urlopen('http://checkip.dyndns.com/').read()) # data = '<html><head>Current IP Check</head><body>Current IP Address: 65.96.168.198</body></html> ' return re.compile(r'Address: (\d+\.\d+\.\d+\.\d+)').search(data).group(1) |
好处:
- 这种方法的一个优点是它是跨平台的
- 它适用于丑陋的NAT(例如你的家用路由器)。
缺点(和解决方法):
- 需要这个网站,不改变的格式(几乎肯定不会),你的DNS服务器工作。通过在发生故障时查询其他第三方IP地址反射器,可以缓解此问题。
- 如果你不查询多个反射器(防止被泄露的反射器告诉你你的地址不是这样的话),或者如果你不使用HTTPS(以防止中间人攻击假装),可能的攻击向量成为服务器)
编辑:虽然最初我认为这些方法非常糟糕(除非你使用很多后备,但代码可能在很多年后都无关紧要),它确实提出了"什么是互联网?"的问题。计算机可能有许多指向许多不同网络的接口。有关该主题的更全面描述,请访问
如果计算机具有到Internet的路由,则即使未正确设置/ etc / hosts,也始终可以获取首选本地IP地址。
1 2 3 4 5 | import socket s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(('8.8.8.8', 1)) # connect() for UDP doesn't send packets local_ip_address = s.getsockname()[0] |
在Linux上:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | >>> import socket, struct, fcntl >>> sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) >>> sockfd = sock.fileno() >>> SIOCGIFADDR = 0x8915 >>> >>> def get_ip(iface = 'eth0'): ... ifreq = struct.pack('16sH14s', iface, socket.AF_INET, '\x00'*14) ... try: ... res = fcntl.ioctl(sockfd, SIOCGIFADDR, ifreq) ... except: ... return None ... ip = struct.unpack('16sH2x4s8x', res)[2] ... return socket.inet_ntoa(ip) ... >>> get_ip('eth0') '10.80.40.234' >>> |
我正在使用以下模块:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | #!/usr/bin/python # module for getting the lan ip address of the computer import os import socket if os.name !="nt": import fcntl import struct def get_interface_ip(ifname): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) return socket.inet_ntoa(fcntl.ioctl( s.fileno(), 0x8915, # SIOCGIFADDR struct.pack('256s', bytes(ifname[:15], 'utf-8')) # Python 2.7: remove the second argument for the bytes call )[20:24]) def get_lan_ip(): ip = socket.gethostbyname(socket.gethostname()) if ip.startswith("127.") and os.name !="nt": interfaces = ["eth0","eth1","eth2","wlan0","wlan1","wifi0","ath0","ath1","ppp0"] for ifname in interfaces: try: ip = get_interface_ip(ifname) break; except IOError: pass return ip |
使用windows和linux进行测试(并且不需要额外的模块)
打算用于基于单个IPv4的LAN中的系统。
固定的接口名称列表不适用于最近的Linux版本,这些版本采用了有关可预测接口名称的systemd v197更改,正如Alexander所指出的那样。
在这种情况下,您需要使用系统上的接口名称手动替换列表,或使用其他解决方案,如netifaces。
我在我的ubuntu机器上使用它:
1 2 3 | import commands commands.getoutput("/sbin/ifconfig").split(" ")[1].split()[1][5:] |
这不起作用。
如果您不想使用外部程序包并且不想依赖外部Internet服务器,这可能会有所帮助。这是我在Google代码搜索中找到并修改为返回所需信息的代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | def getIPAddresses(): from ctypes import Structure, windll, sizeof from ctypes import POINTER, byref from ctypes import c_ulong, c_uint, c_ubyte, c_char MAX_ADAPTER_DESCRIPTION_LENGTH = 128 MAX_ADAPTER_NAME_LENGTH = 256 MAX_ADAPTER_ADDRESS_LENGTH = 8 class IP_ADDR_STRING(Structure): pass LP_IP_ADDR_STRING = POINTER(IP_ADDR_STRING) IP_ADDR_STRING._fields_ = [ ("next", LP_IP_ADDR_STRING), ("ipAddress", c_char * 16), ("ipMask", c_char * 16), ("context", c_ulong)] class IP_ADAPTER_INFO (Structure): pass LP_IP_ADAPTER_INFO = POINTER(IP_ADAPTER_INFO) IP_ADAPTER_INFO._fields_ = [ ("next", LP_IP_ADAPTER_INFO), ("comboIndex", c_ulong), ("adapterName", c_char * (MAX_ADAPTER_NAME_LENGTH + 4)), ("description", c_char * (MAX_ADAPTER_DESCRIPTION_LENGTH + 4)), ("addressLength", c_uint), ("address", c_ubyte * MAX_ADAPTER_ADDRESS_LENGTH), ("index", c_ulong), ("type", c_uint), ("dhcpEnabled", c_uint), ("currentIpAddress", LP_IP_ADDR_STRING), ("ipAddressList", IP_ADDR_STRING), ("gatewayList", IP_ADDR_STRING), ("dhcpServer", IP_ADDR_STRING), ("haveWins", c_uint), ("primaryWinsServer", IP_ADDR_STRING), ("secondaryWinsServer", IP_ADDR_STRING), ("leaseObtained", c_ulong), ("leaseExpires", c_ulong)] GetAdaptersInfo = windll.iphlpapi.GetAdaptersInfo GetAdaptersInfo.restype = c_ulong GetAdaptersInfo.argtypes = [LP_IP_ADAPTER_INFO, POINTER(c_ulong)] adapterList = (IP_ADAPTER_INFO * 10)() buflen = c_ulong(sizeof(adapterList)) rc = GetAdaptersInfo(byref(adapterList[0]), byref(buflen)) if rc == 0: for a in adapterList: adNode = a.ipAddressList while True: ipAddr = adNode.ipAddress if ipAddr: yield ipAddr adNode = adNode.next if not adNode: break |
用法:
1 2 3 4 | >>> for addr in getIPAddresses(): >>> print addr 192.168.0.100 10.5.9.207 |
由于它依赖于
我认为这个版本尚未发布。
我在Ubuntu 12.04上使用python 2.7进行了测试。
在以下网址找到此解决方案:http://code.activestate.com/recipes/439094-get-the-ip-address-associated-with-a-network-inter/
1 2 3 4 5 6 7 8 9 10 11 | import socket import fcntl import struct def get_ip_address(ifname): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) return socket.inet_ntoa(fcntl.ioctl( s.fileno(), 0x8915, # SIOCGIFADDR struct.pack('256s', ifname[:15]) )[20:24]) |
结果示例:
1 2 | >>> get_ip_address('eth0') '38.113.228.130' |
关于Debian(测试),我怀疑大多数Linux的..
1 2 3 | import commands RetMyIP = commands.getoutput("hostname -I") |
在MS Windows上(已测试)
1 2 3 | import socket socket.gethostbyname(socket.gethostname()) |
ninjagecko答案的变化。这应该适用于允许UDP广播的任何LAN,并且不需要访问LAN或Internet上的地址。
1 2 3 4 5 6 7 8 | import socket def getNetworkIp(): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) s.connect(('<broadcast>', 0)) return s.getsockname()[0] print (getNetworkIp()) |
我担心除了连接到另一台计算机并让它向您发送您的IP地址之外,没有任何好的平台独立方法可以做到这一点。例如:findmyipaddress。请注意,如果您需要NAT后面的IP地址,除非您连接的计算机也在NAT后面,否则这将不起作用。
这是一个适用于Linux的解决方案:获取与网络接口关联的IP地址。
通过命令行工具生成"干净"输出的一种简单方法:
1 2 3 4 | import commands ips = commands.getoutput("/sbin/ifconfig | grep -i "inet" | grep -iv "inet6" |" + "awk {'print $2'} | sed -ne 's/addr\:/ /p'") print ips |
它将显示系统上的所有IPv4地址。
仅供参考我可以验证方法:
1 2 | import socket addr = socket.gethostbyname(socket.gethostname()) |
适用于OS X(10.6,10.5),Windows XP和管理良好的RHEL部门服务器。它在一个非常小的CentOS VM上无法工作,我只是做了一些内核攻击。因此,对于该实例,您只需检查127.0.0.1地址,在这种情况下执行以下操作:
1 2 3 4 | if addr =="127.0.0.1": import commands output = commands.getoutput("/sbin/ifconfig") addr = parseaddress(output) |
然后从输出中解析ip地址。应该注意的是,默认情况下ifconfig不在普通用户的PATH中,这就是我在命令中给出完整路径的原因。我希望这有帮助。
这是UnkwnTech的答案的变体 - 它提供了一个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | # imports import errno import socket # localhost prefixes _local_networks = ("127.","0:0:0:0:0:0:0:1") # ignore these prefixes -- localhost, unspecified, and link-local _ignored_networks = _local_networks + ("0.","0:0:0:0:0:0:0:0","169.254.","fe80:") def detect_family(addr): if"." in addr: assert":" not in addr return socket.AF_INET elif":" in addr: return socket.AF_INET6 else: raise ValueError("invalid ipv4/6 address: %r" % addr) def expand_addr(addr): """convert address into canonical expanded form -- no leading zeroes in groups, and for ipv6: lowercase hex, no collapsed groups. """ family = detect_family(addr) addr = socket.inet_ntop(family, socket.inet_pton(family, addr)) if"::" in addr: count = 8-addr.count(":") addr = addr.replace("::", (":0" * count) +":") if addr.startswith(":"): addr ="0" + addr return addr def _get_local_addr(family, remote): try: s = socket.socket(family, socket.SOCK_DGRAM) try: s.connect((remote, 9)) return s.getsockname()[0] finally: s.close() except socket.error: return None def get_local_addr(remote=None, ipv6=True): """get LAN address of host :param remote: return LAN address that host would use to access that specific remote address. by default, returns address it would use to access the public internet. :param ipv6: by default, attempts to find an ipv6 address first. if set to False, only checks ipv4. :returns: primary LAN address for host, or ``None`` if couldn't be determined. """ if remote: family = detect_family(remote) local = _get_local_addr(family, remote) if not local: return None if family == socket.AF_INET6: # expand zero groups so the startswith() test works. local = expand_addr(local) if local.startswith(_local_networks): # border case where remote addr belongs to host return local else: # NOTE: the two addresses used here are TESTNET addresses, # which should never exist in the real world. if ipv6: local = _get_local_addr(socket.AF_INET6,"2001:db8::1234") # expand zero groups so the startswith() test works. if local: local = expand_addr(local) else: local = None if not local: local = _get_local_addr(socket.AF_INET,"192.0.2.123") if not local: return None if local.startswith(_ignored_networks): return None return local |
1 2 | import socket [i[4][0] for i in socket.getaddrinfo(socket.gethostname(), None)] |
这适用于大多数Linux机箱:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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() |
这个答案是我个人尝试解决获取LAN IP的问题,因为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | 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()) |
但是,没有跨平台的方式来获取所有IP地址。在Linux上,您可以使用
那么你可以在GNU / Linux上使用命令"ip route"来了解你当前的IP地址。
这显示了路由器/调制解调器上运行的DHCP服务器为接口提供的IP。通常"192.168.1.1/24"是本地网络的IP,其中"24"表示掩码范围内DHCP服务器给出的可用IP地址范围。
这是一个例子:请注意,PyNotify只是让我的观点直截了当的补充,根本不需要
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #! /usr/bin/env python import sys , pynotify if sys.version_info[1] != 7: raise RuntimeError('Python 2.7 And Above Only') from subprocess import check_output # Available on Python 2.7+ | N/A IP = check_output(['ip', 'route']) Split_Result = IP.split() # print Split_Result[2] # Remove"#" to enable pynotify.init("image") notify = pynotify.Notification("Ip","Server Running At:" + Split_Result[2] ,"/home/User/wireless.png") notify.show() |
这样做的好处是您不需要指定网络接口。这在运行套接字服务器时非常有用
您可以使用easy_install甚至Pip安装PyNotify:
1 | easy_install py-notify |
要么
1 | pip install py-notify |
或者在python脚本/解释器中
1 2 3 | from pip import main main(['install', 'py-notify']) |
稍微改进使用IP命令的命令版本,并返回IPv4和IPv6地址:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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(' ')) #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)] |
如果您正在寻找与本地主机IP地址
1 2 3 4 | import subprocess address = subprocess.check_output(['hostname', '-s', '-I']) address = address.decode('utf-8') address=address[:-1] |
这也可以写成一行:
1 | address = subprocess.check_output(['hostname', '-s', '-I']).decode('utf-8')[:-1] |
即使将
1 2 3 4 5 | import netifaces as ni ni.ifaddresses('eth0') ip = ni.ifaddresses('eth0')[ni.AF_INET][0]['addr'] print(ip) |
这将返回Ubuntu系统和MacOS中的IP地址。输出将是系统IP地址,就像我的IP:192.168.1.10。
注意:这不是使用标准库,而是非常简单。
$ pip install pif
1 2 | from pif import get_public_ip get_public_ip() |
要获取IP地址,您可以直接在python中使用shell命令:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import socket, subprocess def getIpAndHostname(): hostname = socket.gethostname() shell_cmd ="ifconfig | awk '/inet addr/{print substr($2,6)}'" proc = subprocess.Popen([shell_cmd], stdout=subprocess.PIPE, shell=True) (out, err) = proc.communicate() ip_list = out.split(' ') ip = ip_list[0] for _ip in ip_list: try: if _ip !="127.0.0.1" and _ip.split(".")[3] !="1": ip = _ip except: pass return ip, hostname ip_addr, hostname = getIpAndHostname() |
通过pip和easy_install可以获得netifaces。 (我知道,它不是基础,但它可能值得安装。)
netifaces在平台上确实存在一些奇怪之处:
- 可能不会始终包含localhost / loop-back接口(Cygwin)。
- 每个协议列出地址(例如,IPv4,IPv6),并且每个接口列出协议。在某些系统(Linux)上,每个协议 - 接口对都有自己的关联接口(使用interface_name:n表示法),而在其他系统(Windows)上,单个接口将具有每个协议的地址列表。在这两种情况下都有一个协议列表,但它可能只包含一个元素。
这里有一些可以使用的netifaces代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import netifaces PROTO = netifaces.AF_INET # We want only IPv4, for now at least # Get list of network interfaces # Note: Can't filter for 'lo' here because Windows lacks it. ifaces = netifaces.interfaces() # Get all addresses (of all kinds) for each interface if_addrs = [netifaces.ifaddresses(iface) for iface in ifaces] # Filter for the desired address type if_inet_addrs = [addr[PROTO] for addr in if_addrs if PROTO in addr] iface_addrs = [s['addr'] for a in if_inet_addrs for s in a if 'addr' in s] # Can filter for '127.0.0.1' here. |
上面的代码没有将地址映射回其接口名称(对于动态生成ebtables / iptables规则很有用)。所以这是一个版本,它将上面的信息与元组中的接口名称保持在一起:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import netifaces PROTO = netifaces.AF_INET # We want only IPv4, for now at least # Get list of network interfaces ifaces = netifaces.interfaces() # Get addresses for each interface if_addrs = [(netifaces.ifaddresses(iface), iface) for iface in ifaces] # Filter for only IPv4 addresses if_inet_addrs = [(tup[0][PROTO], tup[1]) for tup in if_addrs if PROTO in tup[0]] iface_addrs = [(s['addr'], tup[1]) for tup in if_inet_addrs for s in tup[0] if 'addr' in s] |
而且,不,我不喜欢列表理解。这就是我的大脑最近的工作方式。
以下代码段将打印出来:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | from __future__ import print_function # For 2.x folks from pprint import pprint as pp print(' ifaces = ', end='') pp(ifaces) print(' if_addrs = ', end='') pp(if_addrs) print(' if_inet_addrs = ', end='') pp(if_inet_addrs) print(' iface_addrs = ', end='') pp(iface_addrs) |
请享用!
这不是Pythonic,但它可以在Windows上可靠地运行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | def getWinIP(version = 'IPv4'): import subprocess if version not in ['IPv4', 'IPv6']: print 'error - protocol version must be"IPv4" or"IPv6"' return None ipconfig = subprocess.check_output('ipconfig') my_ip = [] for line in ipconfig.split(' '): if 'Address' in line and version in line: my_ip.append(line.split(' : ')[1].strip()) return my_ip print getWinIP() |
是的,这是一个黑客攻击,但有时候我不想再次猜测操作系统,只是继续使用内置和工作的东西。
我必须解决问题"弄清楚IP地址是否是本地的",我首先想到的是建立一个本地的IP列表然后匹配它。这就是我引发这个问题的原因。但是,我后来意识到有一种更直接的方法:尝试绑定该IP并查看它是否有效。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | _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 |
我知道这并没有直接回答这个问题,但这对任何试图解决相关问题的人都有帮助,而且他们正在遵循同样的思路。这具有作为跨平台解决方案的优势(我认为)。
1 2 | import socket socket.gethostbyname(socket.getfqdn()) |
使用新引入的asyncio包的Python 3.4版本。
1 2 3 4 5 6 7 8 | async get_local_ip(): loop = asyncio.get_event_loop() transport, protocol = await loop.create_datagram_endpoint( asyncio.DatagramProtocol, remote_addr=('8.8.8.8', 80)) result = transport.get_extra_info('sockname')[0]) transport.close() return result |
这是基于UnkwnTech的优秀答案。
有关* nix系统上的IP地址列表,
1 2 3 4 5 | import subprocess co = subprocess.Popen(['ifconfig'], stdout = subprocess.PIPE) ifconfig = co.stdout.read() ip_regex = re.compile('((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-4]|2[0-5][0-9]|[01]?[0-9][0-9]?))') [match[0] for match in ip_regex.findall(ifconfig, re.MULTILINE)] |
虽然这个答案有点晚了,但我认为其他人可能觉得它很有用:-)
PS:它还将返回广播地址和网络掩码。
好的,这是特定于Windows的,并且需要安装python WMI模块,但它似乎比不断尝试调用外部服务器要少得多。这只是另一种选择,因为已经有很多好的选项,但它可能非常适合您的项目。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | Import WMI def getlocalip(): local = wmi.WMI() for interface in local.Win32_NetworkAdapterConfiguration(IPEnabled=1): for ip_address in interface.IPAddress: if ip_address != '0.0.0.0': localip = ip_address return localip >>>getlocalip() u'xxx.xxx.xxx.xxx' >>> |
顺便说一句,WMI是非常强大的...如果你正在做任何远程管理窗口机器,你一定要看看它能做什么。
这与以前发布的答案非常相似,但我找不到任何这种使用的电话。这就是我用于ipv4的内容。对于ipv6更改'。'进入':'in
1 2 3 | import socket print next(i[4][0] for i in socket.getaddrinfo( socket.gethostname(), 80) if '127.' not in i[4][0] and '.' in i[4][0]);" |
对于linux env,读取/ proc / net / tcp,第二个(localaddress)和第三个(remoteaddress)将以hexa格式提供IP。
提示:如果第二列归零(00000000:0000),那么它的监听端口:)
https://github.com/romol0s/python/blob/master/general/functions/getTcpListenIpsByPort.py
https://www.kernel.org/doc/Documentation/networking/proc_net_tcp.txt
可以将以前答案的另一个变体保存到名为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #!/usr/bin/env python import sys, socket if len(sys.argv) > 1: for remote_host in sys.argv[1:]: # determine local host ip by outgoing test to another host # use port 9 (discard protocol - RFC 863) over UDP4 with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s: s.connect((remote_host, 9)) my_ip = s.getsockname()[0] print(my_ip, flush=True) else: import platform my_name = platform.node() my_ip = socket.gethostbyname(my_name) print(my_ip) |
它需要任意数量的远程主机,并打印出本地ips以逐个访问它们:
1 2 3 4 5 | $ my-ip-to z.cn g.cn localhost 192.168.11.102 192.168.11.102 127.0.0.1 $ |
当没有给出arg时打印最好的赌注。
1 2 | $ my-ip-to 192.168.11.102 |
简单又甜蜜!
1 2 3 4 5 6 7 | def getip(): import socket hostname= socket.gethostname() ip=socket.gethostbyname(hostname) return(ip) |
一台机器可以有你提到的多个网络接口(包括本地环回127.0.0.1)。就操作系统而言,它也是一个"真实的IP地址"。
如果要跟踪所有接口,请查看以下Puthon包:http://alastairs-place.net/netifaces/
我想你可以避免让gethostbyname返回127.0.0.1,如果你从hosts文件中省略了loopback条目。 (待核实)。
1 2 3 4 | from netifaces import interfaces, ifaddresses, AF_INET iplist = [ifaddresses(face)[AF_INET][0]["addr"] for face in interfaces() if AF_INET in ifaddresses(face)] print(iplist) ['10.8.0.2', '192.168.1.10', '127.0.0.1'] |
对于linux,你可以像这样使用
1 2 | from subprocess import check_output check_output(['hostname', '-I']) |
我决定使用ipfy的服务和/或API:https://www.ipify.org。
1 2 3 4 5 6 7 8 9 10 | #!/usr/bin/env python3 from urllib.request import urlopen def public_ip(): data = urlopen('https://api.ipify.org').read() return str(data, encoding='utf-8') print(public_ip()) |
响应也可以以JSON和JSONP格式获得。
在Github上有一个ipify Python库。
1 2 | import socket print(socket.gethostbyname(socket.getfqdn())) |