Linux环境下Python获取网段/子网掩码的最快实现方法
Linux下Python获取本机CIDR格式网段实现
实现逻辑
要输出192.168.1.0/24格式的CIDR网段,只需要三个步骤:
- 获取本机实际对外通信的IP地址,避免误拿回环地址
- 读取该IP对应网卡配置的子网掩码
- 将子网掩码转换为前缀长度(如255.255.255.0对应前缀24),通过IP和掩码按位与计算出网络地址,拼接成目标格式
纯标准库实现(无第三方依赖)
不需要安装额外包,直接调用Linux系统提供的ioctl接口读取网卡信息即可,代码如下:
import socket import struct import fcntl def get_local_cidr(): # 获取实际出口IP,规避gethostname绑定回环地址的问题 conn = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: # 无需真正建立连接,仅触发路由选择拿到出口IP conn.connect(('114.114.114.114', 80)) my_ip = conn.getsockname()[0] finally: conn.close() # 查找IP对应的网卡名称 def find_target_iface(target_ip): for _, iface_name in socket.if_nameindex(): sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: iface_info = fcntl.ioctl( sock.fileno(), 0x8915, # SIOCGIFADDR 常量,用于读取网卡IP struct.pack('256s', iface_name[:15].encode('utf-8')) ) iface_ip = socket.inet_ntoa(iface_info[20:24]) if iface_ip == target_ip: return iface_name except OSError: continue finally: sock.close() return None target_iface = find_target_iface(my_ip) if not target_iface: raise RuntimeError("未找到对应IP的网卡设备") # 读取对应网卡的子网掩码 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: mask_info = fcntl.ioctl( sock.fileno(), 0x891b, # SIOCGIFNETMASK 常量,用于读取网卡子网掩码 struct.pack('256s', target_iface[:15].encode('utf-8')) ) netmask = socket.inet_ntoa(mask_info[20:24]) finally: sock.close() # 子网掩码转CIDR前缀长度 def calc_prefix_len(mask_str): return sum(bin(int(segment)).count('1') for segment in mask_str.split('.')) prefix_len = calc_prefix_len(netmask) # 计算网络地址 ip_seg = list(map(int, my_ip.split('.'))) mask_seg = list(map(int, netmask.split('.'))) network_seg = [str(ip_seg[i] & mask_seg[i]) for i in range(4)] network_addr = '.'.join(network_seg) return f"{network_addr}/{prefix_len}" # 调用示例 if __name__ == "__main__": print(get_local_cidr())
注意:你之前用的
socket.gethostbyname(socket.gethostname())存在兼容性问题,如果系统/etc/hosts里把主机名绑定到127.0.0.1,会错误返回环回地址,上述代码通过UDP socket触发路由选路的方式拿IP,结果更准确。
简化实现(依赖第三方库netifaces)
如果可以安装第三方依赖,用netifaces可以省去手写ioctl调用的逻辑,代码更简洁:
- 先安装依赖:
pip install netifaces - 实现代码:
import socket import netifaces def get_local_cidr(): # 获取出口IP conn = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: conn.connect(('114.114.114.114', 80)) my_ip = conn.getsockname()[0] finally: conn.close() # 遍历网卡匹配IP,计算CIDR for iface in netifaces.interfaces(): ip_configs = netifaces.ifaddresses(iface).get(netifaces.AF_INET, []) for config in ip_configs: if config.get('addr') == my_ip: netmask = config.get('netmask') prefix_len = sum(bin(int(seg)).count('1') for seg in netmask.split('.')) ip_seg = list(map(int, my_ip.split('.'))) mask_seg = list(map(int, netmask.split('.'))) network_addr = '.'.join([str(ip_seg[i] & mask_seg[i]) for i in range(4)]) return f"{network_addr}/{prefix_len}" raise RuntimeError("获取CIDR网段失败")
内容的提问来源于stack exchange,提问作者Atropin
相关产品推荐
相关产品推荐

