Python IP地址发现代码提供外部IP而不是eth0设备IP

时间:2014-07-22 19:29:52

标签: python amazon-web-services

我有一个python类,用于获取您所在本地计算机的IP地址。它适用于实际硬件(除非涉及桥接设备的MacOS)或本地VM。这是代码:

class IPAddress:
    ip_address = None

    def __init__(self):
        return

    def _get_interface_ip(self,ifname):
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        return socket.inet_ntoa(fcntl.ioctl(s.fileno(), 0x8915, struct.pack('256s',
                            ifname[:15]))[20:24])

    # does not work on MacOS with bridged devices such as vboxnet0, tap0, tun0
    def get_lan_ip(self):
        hostname = socket.gethostname()
        ip = u''
        try:
            ip = socket.gethostbyname(hostname)
        except socket.gaierror, e:
            try:
                ip = socket.gethostbyname(u'localhost')
            except: pass

        if ip.startswith("127.") and os.name != "nt":
            interfaces = [
                "eth0",
                "eth1",
                "eth2",
                "en0",
                "en1",
                "en2",
                "wlan0",
                "wlan1",
                "wifi0",
                "ath0",
                "ath1",
                "ppp0",
                ]
            for ifname in interfaces:
                try:
                    ip = self._get_interface_ip(ifname)
                    break
                except IOError:
                    pass
        return ip

# Find out this instance
x = IPAddress()
server_ip = x.get_lan_ip()

除了AWS之外,它似乎无处不在。在AWS上,ifconfig eth0提供分配给eth0的内部IP地址,而该类提供与访问实例相关联的外部CNAME&#IP地址(在EC2 Classic中)。

是什么给出的?是否有更好的方法可以使用(例如)boto进行自我发现?

1 个答案:

答案 0 :(得分:2)

首先,我不会使用gethostbyname()或其亲属。这样做依赖于您无法控制的外部数据库,而这些数据库通常不是最新的。

接下来,我不会打电话给ioctl()。任何特定的ioctl的存在,更不用说它的行为,在操作系统中都没有标准化。

如果是我,我会connect()对某些外部服务,然后致电socket.getsockname()

def get_my_addr():
  s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  s.connect(('8.8.8.8', 53))
  return s.getsockname()[0]

如果这不起作用,我会connect()使用基于TCP的服务:

def get_my_addr():
  s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  s.connect(('www.google.com', 80))
  return s.getsockname()[0]