python画图标签 - python3 matplot中文



使用Python的stdlib查找本地IP地址 (20)

我如何在Python平台上独立地找到本地IP地址(即192.168.xx或10.0.xx),并且只使用标准库?


Answer #1

ninjagecko的答案的变化。 这应该适用于任何允许UDP广播的局域网,并且不需要访问局域网或互联网上的地址。

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())

Answer #2

127.0.1.1 is your real IP address. More generally speaking, a computer can have any number of IP addresses. You can filter them for private networks - 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16.

However, there is no cross-platform way to get all IP addresses. On Linux, you can use the SIOCGIFCONF ioctl.


Answer #3

套接字API方法

请参阅https://.com/a/28950776/711085

缺点:

  • 不是跨平台的。
  • 需要更多的回退代码,与Internet上特定地址的存在相关联
  • 如果你在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),例如:

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)

优点:

  • 这种方法的一个优点是它是跨平台的
  • 它从丑陋的NAT(例如你的家庭路由器)后面工作。

缺点(和解决方法):

  • 要求该网站启动,格式不变(几乎肯定不会),并且您的DNS服务器正在工作。 通过在发生故障的情况下查询其他第三方IP地址反射器,可以减轻这个问题。
  • 如果你没有查询多个反射器(为了防止受到攻击的反射器告诉你,你的地址是不是的东西),或者如果你不使用HTTPS(防止假冒中间人攻击成为服务器)

编辑 :尽管最初我认为这些方法非常糟糕(除非你使用了许多后备,代码可能在很多年后都不相关),但它确实提出了“互联网是什么?”的问题。 计算机可能有许多指向许多不同网络的接口。 有关该主题的更全面描述,请访问Google gateways and routes 。 计算机可能能够通过内部网关访问内部网络,或通过网关(例如路由器)访问全球网络(通常是案例)。 OP询问的本地IP地址只针对单个链路层定义好,因此您必须指定(“是网卡还是以太网电缆,我们正在谈论?”) 。 所提出的这个问题可能有多个非唯一的答案。 但是,全球网络上的全球IP地址可能是明确定义的(在没有大规模网络碎片的情况下):可能是通过可访问TLD的网关的返回路径。


Answer #4

该函数返回本地盒子(具有默认路由的那个盒子)上的“主要”IP

  • 不需要可路由的网络访问或任何连接。
  • 即使所有接口都从网络拔出,也可以工作。
  • 不需要甚至尝试去其他任何地方
  • 与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

这将返回一个主要的IP(具有默认路由的IP)。 如果您需要将所有IP连接到所有接口(包括本地主机等),请参阅此答案

如果您在家里使用的无线局域网防火墙等NAT防火墙后面,那么这将不会显示您的公共NAT IP,而是您本地网络上的私有NAT IP,它具有到您本地WIFI路由器的默认路由; 得到你的无线路由器的外部IP地址要么需要在这个盒子上运行这个,要么连接到一个外部服务,如可以反射IP地址的whatismyip.com/whatismyipaddress.com ......但这与原来的问题完全不同。 :)

根据Pedro在评论中的建议更新connect()调用。 (如果您需要特定的许可证声明,这是公共领域/免费用于任何用途,或者MIT / CC2-BY-SA每个堆栈溢出的代码/内容许可证可供选择。)


Answer #5

I had to solve the problem "Figure out if an IP address is local or not", and my first thought was to build a list of IPs that were local and then match against it. This is what led me to this question. However, I later realized there is a more straightfoward way to do it: Try to bind on that IP and see if it works.

_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

I know this doesn't answer the question directly, but this should be helpful to anyone trying to solve the related question and who was following the same train of thought. This has the advantage of being a cross-platform solution (I think).


Answer #6

Note: This is not using the standard library, but quite simple.

$ pip install pif

from pif import get_public_ip
get_public_ip()

Answer #7

Well you can use the command "ip route" on GNU/Linux to know your current IP address.

This shows the IP given to the interface by the DHCP server running on the router/modem. Usually "192.168.1.1/24" is the IP for local network where "24" means the range of posible IP addresses given by the DHCP server within the mask range.

Here's an example: Note that PyNotify is just an addition to get my point straight and is not required at all

#! /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()    

The advantage of this is that you don't need to specify the network interface. That's pretty useful when running a socket server

You can install PyNotify using easy_install or even Pip:

easy_install py-notify

要么

pip install py-notify

or within python script/interpreter

from pip import main

main(['install', 'py-notify'])

Answer #8

netifaces is available via pip and easy_install. (I know, it's not in base, but it could be worth the install.)

netifaces does have some oddities across platforms:

  • The localhost/loop-back interface may not always be included (Cygwin).
  • Addresses are listed per-protocol (eg, IPv4, IPv6) and protocols are listed per-interface. On some systems (Linux) each protocol-interface pair has its own associated interface (using the interface_name:n notation) while on other systems (Windows) a single interface will have a list of addresses for each protocol. In both cases there is a protocol list, but it may contain only a single element.

Here's some netifaces code to play with:

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.

The above code doesn't map an address back to its interface name (useful for generating ebtables/iptables rules on the fly). So here's a version that keeps the above information with the interface name in a tuple:

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]

And, no, I'm not in love with list comprehensions. It's just the way my brain works these days.

The following snippet will print it all out:

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)

请享用!


Answer #9

即时通讯使用以下模块

#!/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的局域网内的系统。

接口名称的固定列表不适用于最近的linux版本,这些版本采用了有关可预测的接口名称的systemd v197更改,如Alexander指出的那样。 在这种情况下,您需要手动将列表替换为系统上的接口名称,或使用其他解决方案(如netifaces


Answer #10

在Debian上(测试过),我怀疑大多数Linux的..

import commands

RetMyIP = commands.getoutput("hostname -I")

在MS Windows上(测试)

import socket

socket.gethostbyname(socket.gethostname())

Answer #11

如果您不想使用外部软件包并且不想依赖外部Internet服务器,这可能会有所帮助。 这是我在Google代码搜索中找到的代码示例,并进行了修改以返回所需的信息:

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

用法:

>>> for addr in getIPAddresses():
>>>    print addr
192.168.0.100
10.5.9.207

因为它依赖于windll ,所以只能在Windows上使用。


Answer #12

如果计算机具有到Internet的路由,则即使/ etc / hosts设置不正确,也会始终获得首选本地IP地址。

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]

Answer #13

您可以使用netifaces模块。 只需输入:

pip install netifaces

在您的命令shell中,它将自行安装在默认的Python安装中。

那么你可以像这样使用它:

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))

在我的电脑上打印:

{45639BDC-1050-46E0-9BE9-075C30DE1FBC}: 192.168.0.100
{D43A468B-F3AE-4BF9-9391-4863A4500583}: 10.5.9.207

该模块的作者声称它可以在Windows,UNIX和Mac OS X上运行。


Answer #14

我不认为这个版本已经发布了。 我在Ubuntu 12.04上使用python 2.7进行了测试。

http://code.activestate.com/recipes/439094-get-the-ip-address-associated-with-a-network-inter/找到此解决方案

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])

示例结果:

get_ip_address('eth0')'38 .113.228.130'


Answer #15

我在我的ubuntu机器上使用这个:

import commands
commands.getoutput("/sbin/ifconfig").split("\n")[1].split()[1][5:]

这不起作用。


Answer #16

这个答案是我个人尝试解决获取LAN IP的问题,因为socket.gethostbyname(socket.gethostname())也返回127.0.0.1。 这种方法不需要Internet就可以连接局域网。 代码适用于Python 3.x,但可以轻松转换为2.x. 使用UDP广播:

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())

Answer #17

这是UnkwnTech答案的变种 - 它提供了一个get_local_addr()函数,它返回主机的主局域网ip地址。 我发布它,因为这增加了一些东西:ipv6支持,错误处理,忽略localhost / linklocal addrs,并使用TESTNET addr(rfc5737)连接到。

# 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

Answer #18

通过命令行实用程序生成“干净”输出的一种简单方法:

import commands
ips = commands.getoutput("/sbin/ifconfig | grep -i \"inet\" | grep -iv \"inet6\" | " +
                         "awk {'print $2'} | sed -ne 's/addr\:/ /p'")
print ips

它将显示系统上的所有IPv4地址。


Answer #19
import socket
[i[4][0] for i in socket.getaddrinfo(socket.gethostname(), None)]

Answer #20
import socket
socket.gethostbyname(socket.getfqdn())




ip-address