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访问权限,并且没有本地代理 .
133
As an alias called myip, that should work everywhere:
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])'"
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地址,则会抛出异常 .
Version that will also work on LANs without an internet connection:
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])
This method returns the "primary" IP on the local box (the one with a default route) .
根本不需要可路由的网络访问或任何连接 .
即使所有接口都从网络上拔下,也能正常工作 .
不需要甚至试图去其他任何地方 .
适用于NAT,公共,私有,外部和内部IP
纯Python 2(或3)没有外部依赖 .
适用于Linux,Windows和OSX .
Python 2或3:
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
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))
from urllib.request import urlopen
import re
def getPublicIp():
data = str(urlopen('http://checkip.dyndns.com/').read())
# data = '<html><head><title>Current IP Check</title></head><body>Current IP Address: 65.96.168.198</body></html>\r\n'
return re.compile(r'Address: (\d+\.\d+\.\d+\.\d+)').search(data).group(1)
或者如果使用python2:
from urllib import urlopen
import re
def getPublicIp():
data = str(urlopen('http://checkip.dyndns.com/').read())
# data = '<html><head><title>Current IP Check</title></head><body>Current IP Address: 65.96.168.198</body></html>\r\n'
return re.compile(r'Address: (\d+\.\d+\.\d+\.\d+)').search(data).group(1)
可能的攻击向量,如果你不't query multiple reflectors (to prevent a compromised reflector from telling you that your address is something it'不),或者如果你不使用HTTPS(以防止假装成服务器的中间人攻击)
编辑:虽然最初我认为这些方法非常糟糕(除非你使用很多后备,但代码可能在很多年后都无关紧要),它确实提出了问题"what is the internet?" . 计算机可能有许多指向许多不同网络的接口 . 有关该主题的更全面描述,请访问 gateways and routes . 计算机可能能够通过内部网关访问内部网络,或通过网关(例如路由器)访问万维网 . OP询问的本地IP地址仅针对单个链路层进行了明确定义,因此您必须指定("is it the network card, or the ethernet cable, which we're talking about?") . 提出的问题可能有多个非唯一的答案 . 然而,万维网上的全球IP地址可能是明确定义的(在没有大规模网络碎片的情况下):可能是通过可以访问TLD的网关的返回路径 .
#!/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
# 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
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)]
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.
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]
而且,不,我不喜欢列表理解 . 这就是我的大脑最近运作的方式 .
以下代码段将打印出来:
from __future__ import print_function # For 2.x folks
from pprint import pprint as pp
print('\nifaces = ', end='')
pp(ifaces)
print('\nif_addrs = ', end='')
pp(if_addrs)
print('\nif_inet_addrs = ', end='')
pp(if_inet_addrs)
print('\niface_addrs = ', end='')
pp(iface_addrs)
请享用!
4
要获取IP地址,您可以直接在 python 中使用shell命令:
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('\n')
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()
30 回答
这总是不起作用(在
/etc/hosts
中作为127.0.0.1
的主机名的机器上返回127.0.0.1
),gimel显示的是paliative,而是使用socket.getfqdn()
. 当然,您的机器需要可解析的主机名 .我刚刚发现这个,但它似乎有点hackish,但是他们说在* nix上尝试了它,我在Windows上做了它并且它有效 .
这假设您具有Internet访问权限,并且没有本地代理 .
As an alias called myip, that should work everywhere:
可正确使用Python 2.x,Python 3.x,现代和旧版Linux发行版,OSX / macOS和Windows查找当前的IPv4地址 .
对于具有多个IP地址,IPv6,未配置IP地址或无法访问Internet的计算机,将无法返回正确的结果 .
Same as above, but only the Python code:
Version that will also work on LANs without an internet connection:
(谢谢@ccpizza)
Background :
使用
socket.gethostbyname(socket.gethostname())
在这里不起作用,因为我所在的计算机之一的/etc/hosts
具有重复的条目和对自身的引用 .socket.gethostbyname()
仅返回/etc/hosts
中的最后一个条目 .这是我最初的尝试,它清除了以
"127."
开头的所有地址:这适用于Linux和Windows上的Python 2和3,但不涉及多个网络设备或IPv6 . 但是,它停止了最近的Linux发行版,所以我尝试了这种替代技术 . 它尝试在
8.8.8.8
端口53
连接到Google DNS服务器:然后我将上述两种技术组合成一个应该可以在任何地方工作的单行程,并在此答案的顶部创建了
myip
别名和Python片段 .随着IPv6的日益普及,以及具有多个网络接口的服务器,使用第三方Python模块来查找IP地址可能比这里列出的任何方法都更加健壮和可靠 .
在Debian(测试)和我怀疑大多数Linux的..
在MS Windows上(已测试)
This method returns the "primary" IP on the local box (the one with a default route) .
根本不需要可路由的网络访问或任何连接 .
即使所有接口都从网络上拔下,也能正常工作 .
不需要甚至试图去其他任何地方 .
适用于NAT,公共,私有,外部和内部IP
纯Python 2(或3)没有外部依赖 .
适用于Linux,Windows和OSX .
Python 2或3:
这将返回一个主要的IP(具有默认路由的IP) . 如果您需要将所有IP连接到所有接口(包括localhost等),请参阅this answer .
如果你在家里的wifi防火墙之后就像NAT防火墙一样,那么这将不会显示你的公共NAT IP,而是显示本地网络上的私有NAT IP,它具有到本地WIFI路由器的默认路由;获取你的wifi路由器的外部IP要么需要在这个盒子上运行,要么连接到可以反映IP的外部服务,例如whatismyip.com/whatismyipaddress.com ......但这与原始问题完全不同 . :)
在评论中根据Pedro的建议更新了connect()调用 . (如果您需要特定的许可声明,这是公共域/免费用于任何用途,或者根据您的选择,每个Stack Overflow的代码/内容许可证可以使用MIT / CC2-BY-SA . )
您可以使用netifaces模块 . 只需输入:
在您的命令shell中,它将自己安装在默认的Python安装上 .
然后你可以像这样使用它:
在我的电脑上打印出来:
该模块的作者声称它应该适用于Windows,UNIX和Mac OS X.
Socket API method
见https://stackoverflow.com/a/28950776/711085
缺点:
不是跨平台的 .
需要更多的后备代码,与互联网上特定地址的存在相关联
如果你在NAT后面,这也行不通
可能创建UDP连接,而不是独立于(通常是ISP 's) DNS availability (see other answers for ideas like using 8.8.8.8: Google' s(巧合也是DNS)服务器)
确保将目标地址设置为UNREACHABLE,例如规格保证未使用的数字IP地址 . 请勿使用fakesubdomain.google.com或somefakewebsite.com等域名;你仍然会发送垃圾邮件(现在或将来),并在此过程中发送自己的网络邮箱 .
Reflector method
(请注意,这不符合OP关于本地IP地址的问题,例如192.168 ......;它会为您提供公共IP地址,根据用例情况,这可能更合适 . )
您可以查询某些网站,例如whatismyip.com(但使用API),例如:
或者如果使用python2:
好处:
这种方法的一个优点是它是跨平台的
它适用于丑陋的NAT(例如你的家用路由器) .
缺点(和解决方法):
要求此网站启动,格式不变(几乎肯定不会),并且您的DNS服务器正常工作 . 通过在发生故障时查询其他第三方IP地址反射器,可以缓解此问题 .
可能的攻击向量,如果你不't query multiple reflectors (to prevent a compromised reflector from telling you that your address is something it'不),或者如果你不使用HTTPS(以防止假装成服务器的中间人攻击)
编辑:虽然最初我认为这些方法非常糟糕(除非你使用很多后备,但代码可能在很多年后都无关紧要),它确实提出了问题"what is the internet?" . 计算机可能有许多指向许多不同网络的接口 . 有关该主题的更全面描述,请访问
gateways and routes
. 计算机可能能够通过内部网关访问内部网络,或通过网关(例如路由器)访问万维网 . OP询问的本地IP地址仅针对单个链路层进行了明确定义,因此您必须指定("is it the network card, or the ethernet cable, which we're talking about?") . 提出的问题可能有多个非唯一的答案 . 然而,万维网上的全球IP地址可能是明确定义的(在没有大规模网络碎片的情况下):可能是通过可以访问TLD的网关的返回路径 .如果计算机具有到Internet的路由,则即使未正确设置/ etc / hosts,也始终可以获取首选本地IP地址 .
在Linux上:
我正在使用以下模块:
使用windows和linux进行测试(并且不需要额外的模块),用于基于单个IPv4的LAN中的系统 .
固定的接口名称列表不适用于最近的Linux版本,这些版本采用了有关可预测接口名称的systemd v197更改,如Alexander所指出的 . 在这种情况下,您需要使用系统上的接口名称手动替换列表,或使用其他解决方案,如netifaces .
我在我的ubuntu机器上使用它:
这不起作用 .
如果您不想依赖外部Internet服务器,这可能会有所帮助 . 这是我在Google Code Search上找到并修改为返回所需信息的代码示例:
用法:
由于它依赖于
windll
,因此仅适用于Windows .我不相信的版本已经发布 . 我在Ubuntu 12.04上使用python 2.7进行了测试 .
在以下位置找到此解决方案:http://code.activestate.com/recipes/439094-get-the-ip-address-associated-with-a-network-inter/
结果示例:
除了连接到另一台计算机并让它发送你的IP地址之外,我还有任何独立于平台的方法 . 例如:findmyipaddress . 请注意,除非您连接的计算机也支持NAT,否则这会在NAT后面赢得't work if you need an IP address that' .
这是一个适用于Linux的解决方案:get the IP address associated with a network interface .
一种通过命令行工具生成“干净”输出的简单方法:
它将显示系统上的所有IPv4地址 .
仅供参考我可以验证方法:
适用于OS X(10.6,10.5),Windows XP和管理良好的RHEL部门服务器 . 它在一个非常小的CentOS VM上无法工作,我只是做了一些内核攻击 . 因此,对于该实例,您只需检查127.0.0.1地址,在这种情况下执行以下操作:
然后从输出中解析ip地址 . 应该注意的是,默认情况下ifconfig不在普通用户的PATH中,这就是我在命令中给出完整路径的原因 . 我希望这有帮助 .
这是UnkwnTech的答案的变体 - 它提供了一个
get_local_addr()
函数,它返回主机的主LAN地址 . 我发布它是因为这增加了许多东西:ipv6支持,错误处理,忽略localhost / linklocal addrs,并使用TESTNET addr(rfc5737)连接 .ninjagecko答案的变化 . 这应该适用于允许UDP广播的任何LAN,并且不需要访问LAN或Internet上的地址 .
这适用于大多数Linux机箱:
这个答案是我个人尝试解决获取局域网IP的问题,因为
socket.gethostbyname(socket.gethostname())
也返回了127.0.0.1 . 此方法不需要Internet只是LAN连接 . 代码适用于Python 3.x,但可以轻松转换为2.x.使用UDP广播:127.0.1.1
是您的真实IP地址 . 更一般地说,计算机可以具有任意数量的IP地址 . 您可以为专用网络过滤它们 - 127.0.0.0/8,10.0.0.0/8,172.16.0.0/12和192.168.0.0/16 .但是,没有跨平台的方式来获取所有IP地址 . 在Linux上,您可以使用SIOCGIFCONF ioctl .
稍微改进使用IP命令的命令版本,并返回IPv4和IPv6地址:
那么你可以在GNU / Linux上使用命令“ip route”来了解你当前的IP地址 .
这显示了DHCP为接口提供的IP服务器在路由器/调制解调器上运行通常“192.168.1.1/24”是本地网络的IP,其中“24”表示掩码范围内DHCP服务器给出的可用IP地址范围 .
这是一个例子:请注意,PyNotify只是一个让我的观点直截了当的补充,根本不需要
这样做的好处是您不需要指定网络接口 . 这在运行套接字服务器时非常有用
您可以使用easy_install甚至Pip安装PyNotify:
要么
或者在python脚本/解释器中
注意:这不是使用标准库,而是非常简单 .
$ pip install pif
netifaces可以通过pip和easy_install获得 . (我知道,它不是基础,但它可能值得安装 . )
netifaces在平台上确实存在一些奇怪之处:
可能并不总是包含localhost / loop-back接口(Cygwin) .
地址按协议列出(例如,IPv4,IPv6),并且每个接口列出协议 . 在某些系统(Linux)上,每个协议 - 接口对都有自己的关联接口(使用interface_name:n表示法),而在其他系统(Windows)上,单个接口将具有每个协议的地址列表 . 在这两种情况下都有一个协议列表,但它可能只包含一个元素 .
这里有一些可以使用的netifaces代码:
上面的代码没有将地址映射回其接口名称(对于动态生成ebtables / iptables规则很有用) . 所以这是一个版本,它将上面的信息与元组中的接口名称保持在一起:
而且,不,我不喜欢列表理解 . 这就是我的大脑最近运作的方式 .
以下代码段将打印出来:
请享用!
要获取IP地址,您可以直接在 python 中使用shell命令:
我必须解决问题“弄清楚IP地址是否是本地的”,我的第一个想法是 Build 一个本地的IP列表然后匹配它 . 这就是我引发这个问题的原因 . 但是,我后来意识到有一种更直接的方法:尝试绑定该IP并查看它是否有效 .
我知道这并没有直接回答这个问题,但是这对任何试图解决相关问题的人都有帮助,并且他们也在遵循同样的思路 . 这具有作为跨平台解决方案的优势(我认为) .
这将返回Ubuntu系统和MacOS中的IP地址 . 输出将是系统IP地址,就像我的IP:192.168.1.10 .