判断ip是否在一个超大ip集中(识别国内ip)

2024-08-24 18:38

本文主要是介绍判断ip是否在一个超大ip集中(识别国内ip),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原文地址: https://www.ikaze.cn/article/65

新需求需要通过ip展示不同语言,由于ip很多,因此字典并不适用,下面给出几个方法。

1. 通过ip位置数据库

比较有名的服务商有:ipip(付费), maxmind (付费),纯真 (免费)。

但在这个应用场景下,我们并不需要具体的位置信息,类似的方案会浪费不必要的内存因此放弃。

2. 利用ip的连续性

后面两个方法有个前提:ip地址列表中大部分是连续的。

这里我们已有了国内ip地址列表(已有开源的库,很好找,另外我用的这个库已经把ip合并为了CIDR格式的地址)。

我们先通过二进制把ip转为可直接比较的数字,再把连续的ip变为 (start_ip, end_ip) 这样的集合,就可以利用二分法快速查找了。

import ipcalcclass ChinaIp:def __init__(self):self.data = []def load(self, cidr_file='data/china_ip_list.txt'):with open(cidr_file, 'r')as f:for s in f.readlines():self.add(s.strip())def add(self, cidr):n = ipcalc.Network(cidr)self.data.append((n.host_first().ip, n.host_last().ip))def search(self, ip):l = 0r = len(self.data) - 1while l <= r:mid = (l + r) // 2if self.data[mid][0] <= ip <= self.data[mid][1]:return Trueelif self.data[mid][0] > ip:r = mid - 1elif self.data[mid][1] < ip:l = mid + 1else:return Falsereturn Falsedef __contains__(self, item):ip = ipcalc.IP(item).ipreturn self.search(ip)china_ip = ChinaIp()
china_ip.load()
print('223.70.163.83' in china_ip)

3. 利用CIDR的特性

CIDR 是形如 x.x.x.x/n 这样的地址,它表示一组网络地址相同的ip,其中n表示前n位作为网络地址。 

根据CIDR的特性,我们可以得到这样的结论:同一CIDR下的ip,其网络地址是相同的。 

因此我们可以把所有国内cidr地址的网络地址取出,放字典;对于一个ip,尝试可能的网络地址(即n),看其是否在字典中。

import ipcalcclass ChinaIp(object):def __init__(self):self.data = {}def load(self, cidr_files='data/china_ip_list.txt'):with open(cidr_files, 'r')as f:cidr_list = f.readlines()for cidr in cidr_list:self.insert(cidr.strip())def insert(self, cidr):network = ipcalc.Network(cidr)self.data[str(network.netmask())]=Truedef __contains__(self, ip):for i in range(1,33):netmask = str(ipcalc.Network(f'{ip}/{i}').netmask())if netmask in self.data:return Truereturn Falsechina_ip = ChinaIp()
china_ip.load()
print('223.70.163.83' in china_ip)

这个算法看起来没啥毛病,但实际测试中速度比第二种慢了很多,耗时的地方在比较时必须循环所有n,而二分法可以快速的排除不可能的部分。

对于这种情况,有两种优化方法:

1. 随机n的列表

class ChinaIp(object):...def __contains__(self, ip):l = list(range(1, 33))random.shuffle(l)for i in l:netmask = str(ipcalc.Network(f'{ip}/{i}').netmask())if netmask in self.data:return Truereturn False

这种方法在测试中,时间减少了一半多。

2. 排除不会出现的n

class ChinaIp(object):def __init__(self):...self.mask_set = set()...def insert(self, cidr):network = ipcalc.Network(cidr)self.data[str(network.netmask())] = Trueself.mask_set.add(network.mask)def __contains__(self, ip):for i in self.mask_set:netmask = str(ipcalc.Network(f'{ip}/{i}').netmask())if netmask in self.data:return Truereturn False

这样优化后速度和第二种持平,不过实际应用中还需要根据ip列表的情况来判断需要用哪种。

这篇关于判断ip是否在一个超大ip集中(识别国内ip)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1103290

相关文章

shell脚本快速检查192.168.1网段ip是否在用的方法

《shell脚本快速检查192.168.1网段ip是否在用的方法》该Shell脚本通过并发ping命令检查192.168.1网段中哪些IP地址正在使用,脚本定义了网络段、超时时间和并行扫描数量,并使用... 目录脚本:检查 192.168.1 网段 IP 是否在用脚本说明使用方法示例输出优化建议总结检查 1

Redis连接失败:客户端IP不在白名单中的问题分析与解决方案

《Redis连接失败:客户端IP不在白名单中的问题分析与解决方案》在现代分布式系统中,Redis作为一种高性能的内存数据库,被广泛应用于缓存、消息队列、会话存储等场景,然而,在实际使用过程中,我们可能... 目录一、问题背景二、错误分析1. 错误信息解读2. 根本原因三、解决方案1. 将客户端IP添加到Re

SpringBoot实现基于URL和IP的访问频率限制

《SpringBoot实现基于URL和IP的访问频率限制》在现代Web应用中,接口被恶意刷新或暴力请求是一种常见的攻击手段,为了保护系统资源,需要对接口的访问频率进行限制,下面我们就来看看如何使用... 目录1. 引言2. 项目依赖3. 配置 Redis4. 创建拦截器5. 注册拦截器6. 创建控制器8.

如何测试计算机的内存是否存在问题? 判断电脑内存故障的多种方法

《如何测试计算机的内存是否存在问题?判断电脑内存故障的多种方法》内存是电脑中非常重要的组件之一,如果内存出现故障,可能会导致电脑出现各种问题,如蓝屏、死机、程序崩溃等,如何判断内存是否出现故障呢?下... 如果你的电脑是崩溃、冻结还是不稳定,那么它的内存可能有问题。要进行检查,你可以使用Windows 11

Linux限制ip访问的解决方案

《Linux限制ip访问的解决方案》为了修复安全扫描中发现的漏洞,我们需要对某些服务设置访问限制,具体来说,就是要确保只有指定的内部IP地址能够访问这些服务,所以本文给大家介绍了Linux限制ip访问... 目录背景:解决方案:使用Firewalld防火墙规则验证方法深度了解防火墙逻辑应用场景与扩展背景:

阿里开源语音识别SenseVoiceWindows环境部署

SenseVoice介绍 SenseVoice 专注于高精度多语言语音识别、情感辨识和音频事件检测多语言识别: 采用超过 40 万小时数据训练,支持超过 50 种语言,识别效果上优于 Whisper 模型。富文本识别:具备优秀的情感识别,能够在测试数据上达到和超过目前最佳情感识别模型的效果。支持声音事件检测能力,支持音乐、掌声、笑声、哭声、咳嗽、喷嚏等多种常见人机交互事件进行检测。高效推

poj 3259 uva 558 Wormholes(bellman最短路负权回路判断)

poj 3259: 题意:John的农场里n块地,m条路连接两块地,w个虫洞,虫洞是一条单向路,不但会把你传送到目的地,而且时间会倒退Ts。 任务是求你会不会在从某块地出发后又回来,看到了离开之前的自己。 判断树中是否存在负权回路就ok了。 bellman代码: #include<stdio.h>const int MaxN = 501;//农场数const int

zoj 1721 判断2条线段(完全)相交

给出起点,终点,与一些障碍线段。 求起点到终点的最短路。 枚举2点的距离,然后最短路。 2点可达条件:没有线段与这2点所构成的线段(完全)相交。 const double eps = 1e-8 ;double add(double x , double y){if(fabs(x+y) < eps*(fabs(x) + fabs(y))) return 0 ;return x + y ;

POJ1269 判断2条直线的位置关系

题目大意:给两个点能够确定一条直线,题目给出两条直线(由4个点确定),要求判断出这两条直线的关系:平行,同线,相交。如果相交还要求出交点坐标。 解题思路: 先判断两条直线p1p2, q1q2是否共线, 如果不是,再判断 直线 是否平行, 如果还不是, 则两直线相交。  判断共线:  p1p2q1 共线 且 p1p2q2 共线 ,共线用叉乘为 0  来判断,  判断 平行:  p1p

Codeforces Round #113 (Div. 2) B 判断多边形是否在凸包内

题目点击打开链接 凸多边形A, 多边形B, 判断B是否严格在A内。  注意AB有重点 。  将A,B上的点合在一起求凸包,如果凸包上的点是B的某个点,则B肯定不在A内。 或者说B上的某点在凸包的边上则也说明B不严格在A里面。 这个处理有个巧妙的方法,只需在求凸包的时候, <=  改成< 也就是说凸包一条边上的所有点都重复点都记录在凸包里面了。 另外不能去重点。 int