2020年4月4日 / 1,523次阅读 / Last Modified 2020年6月6日
socket
编写网络程序,免不了要获取本机的IP地址,在python中,这也是一个技术活。因为似乎直接的方式总是有些让是失望,要采用迂回的方式来获取。
下面我们先看看直接的方式,使用 socket. gethostbyname 这样的函数来获取IP地址:
>>> import socket
>>> hostname = socket.gethostname()
>>> hostname
'DESKTOP-LKS6V4S'
>>> socket.gethostbyname(hostname)
'169.254.237.239'
能获取到IP地址,不过,仔细看看,这个地址有问题,169开头的,不是本机用来访问网络的地址。
原来本机上有好几个IPv4的地址,socket.gethostbyname 只是返回了排在最前面的那一个:
C:\Users\xinli>ipconfig
Windows IP 配置
以太网适配器 Npcap Loopback Adapter:
连接特定的 DNS 后缀 . . . . . . . :
本地链接 IPv6 地址. . . . . . . . : fe80::ed1c:eb46:6409:edef%6
自动配置 IPv4 地址 . . . . . . . : 169.254.237.239
子网掩码 . . . . . . . . . . . . : 255.255.0.0
默认网关. . . . . . . . . . . . . :
无线局域网适配器 WLAN:
媒体状态 . . . . . . . . . . . . : 媒体已断开连接
连接特定的 DNS 后缀 . . . . . . . :
无线局域网适配器 本地连接* 1:
媒体状态 . . . . . . . . . . . . : 媒体已断开连接
连接特定的 DNS 后缀 . . . . . . . :
无线局域网适配器 本地连接* 2:
媒体状态 . . . . . . . . . . . . : 媒体已断开连接
连接特定的 DNS 后缀 . . . . . . . :
以太网适配器 以太网:
连接特定的 DNS 后缀 . . . . . . . : DHCP HOST
本地链接 IPv6 地址. . . . . . . . : fe80::c5a8:e679:2b80:5668%11
IPv4 地址 . . . . . . . . . . . . : 192.168.2.105
子网掩码 . . . . . . . . . . . . : 255.255.255.0
默认网关. . . . . . . . . . . . . : 192.168.2.1
以太网适配器 VMware Network Adapter VMnet1:
连接特定的 DNS 后缀 . . . . . . . :
本地链接 IPv6 地址. . . . . . . . : fe80::d554:a5b1:d09:d566%19
IPv4 地址 . . . . . . . . . . . . : 192.168.153.1
子网掩码 . . . . . . . . . . . . : 255.255.255.0
默认网关. . . . . . . . . . . . . :
以太网适配器 VMware Network Adapter VMnet8:
连接特定的 DNS 后缀 . . . . . . . :
本地链接 IPv6 地址. . . . . . . . : fe80::8cbf:c78a:18a1:4705%17
IPv4 地址 . . . . . . . . . . . . : 192.168.78.1
子网掩码 . . . . . . . . . . . . : 255.255.255.0
默认网关. . . . . . . . . . . . . :
python的socket模块,还有一个 gethostbyname_ex 函数,可以试一下:
>>> socket.gethostbyname_ex(hostname)
('DESKTOP-LKS6V4S', [], ['169.254.237.239', '192.168.78.1', '192.168.153.1', '192.168.2.105'])
稍微好一点,这个函数把本机所有的IPv4地址都返回了,但是我们要使用哪一个区访问Internet,还是不得而知。gethostbyname* 函数只能支持IPv4,如果要支持IPv6,需要用到 getaddrinfo 函数:
>>> socket.getaddrinfo(hostname, None)
[(, 0, 0, '', ('fe80::ed1c:eb46:6409:edef', 0, 0, 6)), (, 0, 0, '', ('fe80::8cbf:c78a:18a1:4705', 0, 0, 17)), (, 0, 0, '', ('fe80::d554:a5b1:d09:d566', 0, 0, 19)), (, 0, 0, '', ('fe80::c5a8:e679:2b80:5668', 0, 0, 11)), (, 0, 0, '', ('169.254.237.239', 0)), (, 0, 0, '', ('192.168.78.1', 0)), (, 0, 0, '', ('192.168.153.1', 0)), (, 0, 0, '', ('192.168.2.105', 0))]
getaddrinfo将本地所有IP地址都返回了。
回到正题,我们应该如何有效获取本机的可以连接Internet的IPv4地址呢?我的答案是,可以采用一个迂回的方式,通过创建一个UDP socket,来间接获取可以访问Internet的那个地址(python底层是怎么运作的,我还没搞清楚):
def get_network_ip():
"""get the local network ip, not loopback 127.*"""
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('1.1.1.1',80))
ip = s.getsockname()[0]
s.close()
return ip
创建一个UDP,随便去连接一个什么地址,然后获取本机的IPv4地址!此方法在Window和Linux下都很好用,亲测!
-- EOF --
本文链接:https://www.pynote.net/archives/1841
《用python有效获取本机IP地址》有2条留言
前一篇:用python连接SMTP的TLS(587端口)发邮件
后一篇:During handling of the above exception, another exception occurred是如何发生的?
Ctrl+D 收藏本页
©Copyright 麦新杰 Since 2019 Python笔记
get_network_ip函数所用的方法,可能在系统启动的时候,出现异常! [ ]
抛出的是一个OSError,network unreachable,有可能是在那一瞬间,网口还没有完全启动,或者还在等待自己的DHCP服务器分配的ip地址。 [ ]