Finding local IP addresses using Python's stdlib

后端 未结 30 2607
北恋
北恋 2020-11-21 23:54

How can I find local IP addresses (i.e. 192.168.x.x or 10.0.x.x) in Python platform independently and using only the standard library?

相关标签:
30条回答
  • 2020-11-22 00:35

    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])'"
    
    • Works correctly with Python 2.x, Python 3.x, modern and old Linux distros, OSX/macOS and Windows for finding the current IPv4 address.
    • Will not return the correct result for machines with multiple IP addresses, IPv6, no configured IP address or no internet access.

    NOTE: If you intend to use something like this within a Python program, the proper way is to make use of a Python module that has IPv6 support.


    Same as above, but only the Python code:

    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])
    
    • This will throw an exception if no IP address is configured.

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

    (thanks @ccpizza)


    Background:

    Using socket.gethostbyname(socket.gethostname()) did not work here, because one of the computers I was on had an /etc/hosts with duplicate entries and references to itself. socket.gethostbyname() only returns the last entry in /etc/hosts.

    This was my initial attempt, which weeds out all addresses starting with "127.":

    import socket
    print([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][:1])
    

    This works with Python 2 and 3, on Linux and Windows, but does not deal with several network devices or IPv6. However, it stopped working on recent Linux distros, so I tried this alternative technique instead. It tries to connect to the Google DNS server at 8.8.8.8 at port 53:

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

    Then I combined the two above techniques into a one-liner that should work everywhere, and created the myip alias and Python snippet at the top of this answer.

    With the increasing popularity of IPv6, and for servers with multiple network interfaces, using a third-party Python module for finding the IP address is probably both more robust and reliable than any of the methods listed here.

    0 讨论(0)
  • 2020-11-22 00:35

    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.

    0 讨论(0)
  • 2020-11-22 00:36

    If the computer has a route to the Internet, this will always work to get the preferred local ip address, even if /etc/hosts is not set correctly.

    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]
    
    0 讨论(0)
  • 2020-11-22 00:37

    A slight refinement of the commands version that uses the IP command, and returns IPv4 and IPv6 addresses:

    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)]
    
    0 讨论(0)
  • 2020-11-22 00:37

    For linux, you can just use check_output of the hostname -I system command like so:

    from subprocess import check_output
    check_output(['hostname', '-I'])
    
    0 讨论(0)
  • 2020-11-22 00:37

    To get the ip address you can use a shell command directly in python:

    import socket, subprocess
    
    def get_ip_and_hostname():
        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 = get_ip_and_hostname()
    
    0 讨论(0)
提交回复
热议问题