前言
引出問題:
在參考網(wǎng)上獲取 IP 地址的代碼,具體實現(xiàn)如下:
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,
struct.pack('256s', ifname[:15]))[20:24])
get_ip_address('eth0')
由于使用的是 Window 系統(tǒng),所以不可避免的出現(xiàn)了錯誤,報錯如下:
from fcntl import ioctl
ImportError: No module named fcntl
網(wǎng)上搜索相關(guān)解決方法,因為 Python 缺少對應(yīng)的 fcntl 模塊,這個模塊是 Python 自帶的,但 Windows 好像沒有。由于代碼實現(xiàn)比較簡單,網(wǎng)上就給了該模塊的實現(xiàn)代碼,如下:
def fcntl(fd, op, arg=0):
return 0
def ioctl(fd, op, arg=0, mutable_flag=True):
if mutable_flag:
return 0
else:
return ""
def flock(fd, op):
return
def lockf(fd, operation, length=0, start=0, whence=0):
return
將該部分代碼保存為 fcntl.py,并存放在 Python 的安裝目錄下,類似于:
D:\Soft_Install\Python37\Lib
。
終于不再報上述的錯誤后,但是獲取 IP 仍然存在問題。
struct.pack('256s', IFNAME[:15])
struct.error: argument for 's' must be a bytes object
修改成如下模式:
struct.pack(b'256s', ifname[:15].encode("utf-8"))
,再次執(zhí)行,得到如下結(jié)果:
TypeError: 'int' object is not subscriptable
究其原因,是因為
fcntl.ioctl(s.fileno(),0x8915,struct.pack(b'256s', ifname[:15].encode("utf-8")))
返回結(jié)果為 0。
網(wǎng)上再次搜索了很久,都沒有找到合適的解決方案,因此決定換個方式實現(xiàn)獲取 IP 地址。
分析
IP 獲取
通過 Python 代碼實現(xiàn) IP 地址獲取,首先需要在本機上找到需要獲取的 IP 地址。獲取 IP 的手段簡單分為兩種,分別在百度搜 ip 查詢,查詢到本機的 public ip 如第一張圖,再利用 ipconfig 查詢到自身 ip 如第二張圖。我們能看到這兩個地址是不同的,那么不是說,每個主機都只有一個 ip 地址么,為什么我們查到的兩個 Ip 地址不一樣呢。
詳細講解可自行前往 IP 講解進行學習,這里只總結(jié)一下:
ipconfig 查出來的是你本機的 IP 地址,也就是內(nèi)網(wǎng)私有地址,此類地址僅在局域網(wǎng)使用,不能聯(lián)通外網(wǎng)。
百度查出來的地址是你上網(wǎng)的共有地址,也許并不是你主機的地址,而是電信或聯(lián)通分給你的地址,用于連接互聯(lián)網(wǎng)。
Python 代碼實現(xiàn)
一、Windows 上實現(xiàn)
import os
import socket
def get_window_ip1():
"""
查詢本機ip地址
:return: ip
"""
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('8.8.8.8', 80))
print(s.getsockname())
ip = s.getsockname()[0]
finally:
s.close()
return ip
def get_window_ip2():
# 獲取本機計算機名稱
hostname = socket.gethostname()
# 需要注意的是,如果本機有多網(wǎng)卡,比如說安裝的有虛擬機,則此ip可能是虛擬機VMnet8的ip,而你真正的內(nèi)網(wǎng)IP可能是物理無線適配器wlan的IP
ip = socket.gethostbyname(hostname)
#這種情況下,首先需要獲取所有網(wǎng)卡的ip地址,然后人為進行篩選
ipList = socket.gethostbyname_ex(hostname)
return ipList[2][-1]
def get_window_ip3():
return [a for a in os.popen('route print').readlines() if ' 0.0.0.0 ' in a][0].split()[-2]
def get_window_ip4():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('baidu.com', 0))
ipaddr = s.getsockname()[0]
return ipaddr
二、Linux 上實現(xiàn)
1、
def get_ip_address():
# 獲取本機計算機名稱
hostname = socket.gethostname()
ip = socket.gethostbyname(hostname)
#下面這兩種種方法同樣可以
# fqdnName = socket.getfqdn(socket.gethostname())
# ip = socket.gethostbyname(fqdnName)
# s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# s.connect(('baidu.com', 0))
# ip = s.getsockname()[0]
return ip
同在 Windows 上使用,上述方法在 Linux 下也可以獲取到正確的 IP 地址。
2、
import socket
import fcntl
import struct
IFNAME = 'eth0'
def get_ip_address(ifname=IFNAME):
'''獲取網(wǎng)卡的ip地址'''
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])
如果遇到報錯
IOError: [Errno 19] No such device
,說明當前 Linux 系統(tǒng)沒有 eth0 網(wǎng)卡。在之前的博客 Centos7 使用 yum 命令遇到的問題總結(jié)一文中,為了聯(lián)網(wǎng)修改網(wǎng)卡配置文件,當時修改的是叫做 ens33 的網(wǎng)卡,可以通過
ip addr
命令查看當前系統(tǒng)的網(wǎng)卡信息。在驗證 IP 獲取代碼的過程中,將“enth0”改為“ens33”,即可獲取正確 IP 信息。如果想要將 ens33 網(wǎng)卡改為 eth0 網(wǎng)卡,可以參考 CentOS7沒有eth0網(wǎng)卡一文進行修改。
3、
def get_ip_address():
# Use ip route list
import subprocess
arg = 'ip route list'
p = subprocess.Popen(arg, shell=True, stdout=subprocess.PIPE)
data = p.communicate()
sdata = data[0].split()
ipaddr = sdata[sdata.index('src') + 1] #ip
netdev = sdata[sdata.index('dev') + 1] #網(wǎng)卡信息
return (ipaddr, netdev)
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
