hao同学的技术博客

  • 首页
  • Java
    • Java
    • JVM教程
    • Java面试
    • Java并发入门
    • Java并发进阶
  • 项目
    • 从零打造项目
  • Python
    • Python
    • Python爬虫
    • 算法
  • Java框架
    • Spring
    • SpringBoot
  • 前端
    • Angular
  • 其他
    • Linux
    • SQL
  • 随笔
分享技术,记录人生
一个痴迷于技术的厨艺爱好者
  1. 首页
  2. Python
  3. 正文

Python获取本机IP地址

2022年5月25日 580点热度 0人点赞 0条评论

Python获取本机IP地址插图

前言

引出问题:

在参考网上获取 IP 地址的代码,具体实现如下:

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 系统,所以不可避免的出现了错误,报错如下:

 from fcntl import ioctl
ImportError: No module named fcntl

网上搜索相关解决方法,因为 Python 缺少对应的 fcntl 模块,这个模块是 Python 自带的,但 Windows 好像没有。由于代码实现比较简单,网上就给了该模块的实现代码,如下:

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")),再次执行,得到如下结果:

TypeError: 'int' object is not subscriptable

究其原因,是因为 fcntl.ioctl(s.fileno(),0x8915,struct.pack(b'256s', ifname[:15].encode("utf-8"))) 返回结果为 0。

网上再次搜索了很久,都没有找到合适的解决方案,因此决定换个方式实现获取 IP 地址。

分析

IP 获取

通过 Python 代码实现 IP 地址获取,首先需要在本机上找到需要获取的 IP 地址。获取 IP 的手段简单分为两种,分别在百度搜 ip 查询,查询到本机的 public ip 如第一张图,再利用 ipconfig 查询到自身 ip 如第二张图。我们能看到这两个地址是不同的,那么不是说,每个主机都只有一个 ip 地址么,为什么我们查到的两个 Ip 地址不一样呢。

图一

在这里插入图片描述

详细讲解可自行前往 IP 讲解进行学习,这里只总结一下:

ipconfig 查出来的是你本机的 IP 地址,也就是内网私有地址,此类地址仅在局域网使用,不能联通外网。
百度查出来的地址是你上网的共有地址,也许并不是你主机的地址,而是电信或联通分给你的地址,用于连接互联网。

Python 代码实现

一、Windows 上实现

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()
    # 需要注意的是,如果本机有多网卡,比如说安装的有虚拟机,则此ip可能是虚拟机VMnet8的ip,而你真正的内网IP可能是物理无线适配器wlan的IP
    ip = socket.gethostbyname(hostname)

    #这种情况下,首先需要获取所有网卡的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 上实现

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):
    '''获取网卡的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 系统没有 eth0 网卡。在之前的博客 Centos7 使用 yum 命令遇到的问题总结一文中,为了联网修改网卡配置文件,当时修改的是叫做 ens33 的网卡,可以通过 ip addr命令查看当前系统的网卡信息。在验证 IP 获取代码的过程中,将“enth0”改为“ens33”,即可获取正确 IP 信息。如果想要将 ens33 网卡改为 eth0 网卡,可以参考 CentOS7没有eth0网卡一文进行修改。

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]  #网卡信息
    return (ipaddr, netdev)
本作品采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可
标签: Python
最后更新:2022年5月25日

hresh

这是一个专注于IT技术学习交流的个人技术博客网站,包括Java学习、Python爬虫、Web开发实践等领域,深耕Java领域,内容涵盖Java基础、Java并发编程、Java虚拟机、Java面试等核心知识点。

点赞
< 上一篇

文章评论

取消回复

hresh

这是一个专注于IT技术学习交流的个人技术博客网站,包括Java学习、Python爬虫、Web开发实践等领域,深耕Java领域,内容涵盖Java基础、Java并发编程、Java虚拟机、Java面试等核心知识点。

文章目录
  • 前言
  • 分析
最新 热点 随机
最新 热点 随机
后端必知:遵循Google Java规范并引入checkstyle检查 Spring Security结合Redis实现缓存功能 Spring Security结合JWT实现认证与授权 Spring Security自定义认证逻辑实现图片验证码登录 Spring Security进阶学习 Spring Security入门学习
Python 中 with 语句的学习 Java并发编程入门学习之线程池 String类之字符串常量池与intern方法 深入学习方法内联 后端必知:遵循Google Java规范并引入checkstyle检查 聊聊Java的数据类型

COPYRIGHT © 2022 hao同学的技术博客. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

鄂ICP备2022007381号

鄂公网安备 42010302002449号