Python IP地址相关的判断

本文介绍如何将点分十进制IP地址转换为整数,并提供判断IP地址合法性的方法。此外,还展示了如何确定两个IP地址是否位于同一局域网、判断IP是否为内网地址及测试端口连通性的技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

点分十进制IP地址转int


import sys
if sys.version_info > (3, 0):
    from functools import reduce

# 点分十进制IP地址转int
def ip_into_int(ip):
    return reduce(lambda x,y:(x<<8)+y,map(int,ip.split('.')))

获取本机IP(点分十进制)

import sys
import socket
# 操作系统类型
SYSTEM_PLATFORM = platform.system()

def get_my_ip():
    if SYSTEM_PLATFORM == 'Windows':
        #获取计算机名称
        hostname = socket.gethostname()
        return socket.gethostbyname(hostname)
    elif SYSTEM_PLATFORM == 'Linux':
        for net_name in netifaces.interfaces():
            if 'ens' not in net_name:
                continue
            s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            return socket.inet_ntoa(fcntl.ioctl(s.fileno(), 0x8915, struct.pack('256s', bytes(net_name[:15],'utf-8')))[20:24])
            # 另一种可行方法
            # netifaces.ifaddresses(net_name)[netifaces.AF_INET][0]['addr']

判断点分十进制IP合法性

import re

def legit_ip(_ip):
    compile_ip = re.compile('^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$')
    if compile_ip.match(_ip):
        return True
    else:
        return False

判断本机与指定IP是否处于同一局域网

# 子网掩码
SUB_MASK = '255.255.255.0'

def is_same_LAN(ip):
    my_ip = get_my_ip()
    # 如果本机没有联网或指定的IP不合法
    if my_ip == '127.0.0.1' or not legit_ip(ip):
        return False
    my_ip = ip_into_int(my_ip)
    ip = ip_into_int(ip)
    mask = ip_into_int(SUB_MASK)
    if my_ip & mask == ip & mask:
        return True
    else:
        return False

判断是否为内网IP

def is_internal_ip(ip):
    ip = ip_into_int(ip)
    net_a = ip_into_int('10.255.255.255') >> 24
    net_b = ip_into_int('172.31.255.255') >> 20
    net_c = ip_into_int('192.168.255.255') >> 16
    return ip >> 24 == net_a or ip >>20 == net_b or ip >> 16 == net_c

测试指定IP端口是否可连通

def IsOpen(ip, port, timeout): # timeout是超时时间
        if isinstance(ip, int):
            ip = int_to_ip(ip)
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.settimeout(timeout)
        try:
            s.connect((ip, int(port)))
            s.shutdown(0.1)
            return True
        except:
            return False

扫描局域网内开放指定端口的计算机,返回IP地址列表

# 局域网扫描单个IP等待时间(s)
ScanPeerTimeout = 0.1

def scan_peer(port):
    my_ip = get_my_ip()
    if my_ip == '127.0.0.1':
        return []
    my_ip = ip_to_int(my_ip)
    mask = ip_to_int(SUB_MASK)
    subnet = my_ip & mask
    subnet_range = mask ^ ip_to_int('255.255.255.255')
    return [int_to_ip(i) for i in range(subnet + 1, subnet + subnet_range) if IsOpen(i, port, ScanPeerTimeout)]

<think>嗯,用户现在问的是Python中有什么方法可以判断IP地址。我需要先理解用户的需求。他们可能想验证一个字符串是否是有效的IP地址,可能是IPv4或IPv6。接下来,我得回想Python的标准库中有没有相关的模块。 首先,记得Python有一个ipaddress模块,是专门处理IP地址的。这个模块可以用来创建、操作和验证IPv4和IPv6地址及网络。用户可能想用这个模块来检查一个字符串是否符合IP地址的格式。比如,他们可能输入一个字符串,想知道它是否是有效的IPv4或IPv6地址。 不过,用户可能不太熟悉这个模块,或者他们可能希望用其他方法,比如正则表达式。这时候需要考虑不同的方法之间的优缺点。比如,使用ipaddress模块更简单,而且可以处理各种情况,比如网络掩码、子网等,但如果是简单的验证,正则表达式可能更快,不过正则表达式写起来容易出错,尤其是IPv6的格式比较复杂。 接下来,我需要考虑用户可能的错误输入情况。例如,用户可能输入类似“192.168.1.256”这样的无效IPv4地址,或者“2001:db8::8a2e:37023:7334”这样的无效IPv6地址。使用ipaddress模块的话,在尝试创建IPv4或IPv6对象时,如果地址无效,会抛出ValueError异常,因此可以通过捕获异常来判断是否有效。 另外,用户可能想知道如何区分IPv4和IPv6地址。这时候可以用ipaddress模块中的IPv4Address和IPv6Address类,分别尝试实例化,如果成功则是相应的类型,否则捕获异常。 还有可能用户需要兼容处理两种类型的IP地址,或者需要同时支持两种类型。这时候可以编写一个函数,先尝试IPv4,如果失败再尝试IPv6,或者同时检查。 另外,可能要考虑用户是否在处理网络请求,比如从用户输入或配置文件中获取的字符串需要验证。这时候使用标准库的方法会更可靠,避免自己编写复杂的正则表达式。 不过,如果用户使用的Python版本较旧,比如低于3.3,那么ipaddress模块可能不可用。这时候可能需要用其他方法,比如正则表达式或者socket模块的inet_pton函数。不过现在大多数情况下,Python3.3及以上版本已经普及,所以推荐使用ipaddress模块。 另外,用户可能想知道是否有更简洁的方法,或者有没有第三方库可用。但通常来说,标准库的方法已经足够,不需要额外安装库。 总结可能的解决方案: 1. 使用ipaddress模块的IPv4Address和IPv6Address类,捕获异常来判断是否有效。 2. 使用正则表达式分别匹配IPv4和IPv6的格式。 3. 使用socket模块的inet_pton函数来验证地址的有效性。 接下来需要比较这些方法的优缺点: - ipaddress模块:官方推荐,处理全面,支持IPv4和IPv6,还能处理网络地址和子网等,但需要处理异常,可能稍微慢一些。 - 正则表达式:速度快,但编写正确的正则表达式比较困难,尤其是IPv6的格式比较复杂,容易出错。 - socket模块:使用底层函数,但需要处理不同的地址族(AF_INET和AF_INET6),并且需要捕获可能的异常,可能不够直观。 用户可能需要一个简单的函数,输入字符串,返回是否是有效的IPv4或IPv6地址。这时候用ipaddress模块是最合适的,因为代码简洁,可读性好。 另外,用户可能希望函数返回具体的类型(IPv4还是IPv6),或者只是布尔值。这时候可以在函数中分别尝试创建IPv4Address和IPv6Address对象,如果都不成功则返回False。 编写示例代码时,需要注意异常处理,比如使用try-except块来捕获ValueError,并处理可能的其他错误。 另外,可能需要考虑IPv4地址的映射IPv6格式,比如::ffff:192.168.1.1,这时候ipaddress模块也能正确识别,但用户是否需要考虑这种情况取决于他们的具体需求。 最后,总结回答,给出使用ipaddress模块的方法,并提供示例代码,说明如何验证IPv4、IPv6,以及同时验证两者的方法,可能再附上正则表达式的例子作为补充,但提醒用户正则表达式的潜在问题。</think>在 Python 中,判断一个字符串是否为有效的 IP 地址IPv4 或 IPv6)可以通过以下方法实现: --- ### 1. **使用 `ipaddress` 模块(推荐)** Python 标准库中的 `ipaddress` 模块专门用于处理 IP 地址和网络,可以直接验证字符串是否为合法的 IPv4/IPv6 地址。 #### 示例代码: ```python import ipaddress def is_valid_ip(address): try: # 尝试解析为 IPv4 或 IPv6 ipaddress.ip_address(address) return True except ValueError: return False # 测试 print(is_valid_ip("192.168.1.1")) # True(IPv4) print(is_valid_ip("2001:db8::1")) # True(IPv6) print(is_valid_ip("256.0.0.1")) # False(无效 IPv4) print(is_valid_ip("192.168.1.1:80")) # False(包含端口) ``` #### 区分 IPv4 和 IPv6: ```python def check_ip_type(address): try: ip = ipaddress.ip_address(address) if isinstance(ip, ipaddress.IPv4Address): return "IPv4" elif isinstance(ip, ipaddress.IPv6Address): return "IPv6" except ValueError: return "Invalid IP" print(check_ip_type("8.8.8.8")) # 输出 "IPv4" print(check_ip_type("2001:db8::1")) # 输出 "IPv6" print(check_ip_type("invalid")) # 输出 "Invalid IP" ``` --- ### 2. **使用正则表达式** 通过正则表达式匹配 IPv4 和 IPv6 的格式规则(适用于简单场景,但不如 `ipaddress` 严谨)。 #### IPv4 正则表达式: ```python import re def is_valid_ipv4(address): pattern = r"^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$" return re.match(pattern, address) is not None print(is_valid_ipv4("192.168.1.1")) # True print(is_valid_ipv4("256.0.0.1")) # False ``` #### IPv6 正则表达式(简化版): ```python def is_valid_ipv6(address): pattern = r"^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|^::([0-9a-fA-F]{1,4}:){0,6}[0-9a-fA-F]{1,4}$|^([0-9a-fA-F]{1,4}:){1,6}:" return re.match(pattern, address) is not None print(is_valid_ipv6("2001:db8::1")) # True print(is_valid_ipv6("2001::db8::1")) # False(重复 ::) ``` --- ### 3. **使用 `socket` 模块** 通过 `socket.inet_pton` 函数验证地址格式(需指定地址族 `AF_INET` 或 `AF_INET6`)。 #### 示例代码: ```python import socket def is_valid_ip(address): try: # 尝试解析为 IPv4 socket.inet_pton(socket.AF_INET, address) return True except socket.error: try: # 尝试解析为 IPv6 socket.inet_pton(socket.AF_INET6, address) return True except socket.error: return False print(is_valid_ip("192.168.1.1")) # True print(is_valid_ip("2001:db8::1")) # True print(is_valid_ip("invalid")) # False ``` --- ### 方法对比 | **方法** | **优点** | **缺点** | |----------------------|-----------------------------------|-----------------------------------| | `ipaddress` 模块 | 官方标准,支持全面(地址、子网等) | 需要处理异常,不兼容 Python 2.x | | 正则表达式 | 灵活,不依赖库 | IPv6 正则复杂,易漏判/误判 | | `socket` 模块 | 底层实现,高效 | 需分别验证 IPv4 和 IPv6 | --- ### 总结 - **推荐使用 `ipaddress` 模块**:直接、安全,符合 Python 最佳实践。 - **正则表达式**:适用于简单场景,但需谨慎编写。 - **特殊需求**:若需兼容旧版 Python(<3.3),可使用 `socket` 模块。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值