一种IP命中交叉网段的查找算法

本文介绍了一种处理大量IP地址和网段信息的高效算法,通过将网段拆分为不交叉段并采用二分查找,大幅提高了IP定位速度,减少查找耗时3个数量级。

1.问题描述

假设有一堆网段,如下所示:

192.168.1.100-192.168.1.120,AAA,id1

192.168.1.50-192.168.1.150,BBB,id2

10.67.1.1/24,CCC,id3

10.67.1.1,DDD,id4

10.67.1.0,EEE,id5

 

第一列是单IP或者网段,第二列是设备hash,第三列是这个IP或者网段的唯一标志。IP与网段、网段与网段之间是可以有交叉的,比如192.16.1.100-192.168.1.120和192.168.1.50-192.168.1.150就是存在一部分交叉的。

 

要求,当一个日志过来过来时,需要得到它里面的IP的唯一ID,比如10.67.1.125过来,我们就知道它是属于10.67.1.1/24网段,那么就是用id3来标志它;比如10.67.1.1过来时,我们发现既可以命中10.67.1.1(id4)也可以命中10.67.1.1/24(id3),那么就提取日志里记录的hash值,比如hash是CCC,那么我们就知道它的唯一ID应该是id3。

 

2.解题思路

1.首先将网段拆开为多个不交叉的段,并且记录每个段对应的相关信息

2.在一个日志过来时,提取其IP在网段里进行二分查找,当查找到的相关信息唯一时,直接返回;当查找到的相关信息不唯一时,使用hash值进行比对,从而拿到命中值

2.1网段拆分为不交叉段

对于一组数据,如下所示:

s1,e1,id1

s2,e2,id2

s3,e3,id3

s和e分别代表起始数值,id为唯一标志。它们的范围如下图所示:

我们可以按数值的大小进行排序,注意,如果两个值相等的情况下,起始值排在结束值之前,排序之后如下所示:

s1,s2,s3,e1,e2,e3

分析的过程如下图所示:

在step1,得到的结果应该是:[s1,s2-1]  id1

在step2,得到的结果应该是:[s2,s3-1]  id1,id2

在step3,得到的结果应该是:[s3,e1]   id1,id2,id3

在step4,得到的结果应该是:[e1+1,e2]   id2,id3

在step5,得到的结果应该是:[e2+1,e3]  id3

那么总结的处理过程如下:

从排序后的数值list里拿到两个元素n1,n2,用一个全局的S记录id值

  • 如果n1是s类型,则a=n1,且将n1对应的id加入S中;如果n1是e类型,则a=n1+1,则将n1对应的id从S中移除
  • 如果n2是s类型,则b=n2-1;如果n2是e类型,则b=n2
  • 如果a<=b且S不为空,则对于[a,b]以及S进行输出

以此循环,直至对于list处理结束。

核心代码如下所示:

public List<OutputNode> init(List<IpRangeAsset> list){
		List<GapRangeNode> gapRangeNodeList = new ArrayList<>();
		for(int i=0;i<list.size();i++){
			gapRangeNodeList.add(new GapRangeNode(list.get(i).getStartIpInt(),i,false));
			gapRangeNodeList.add(new GapRangeNode(list.get(i).getEndIpInt(),i,true));
		}

		Collections.sort(gapRangeNodeList, new Comparator<GapRangeNode>() {
			@Override
			public int compare(GapRangeNode o1, GapRangeNode o2) {
				return o1.getNumber()-o2.getNumber()<0||(o1.getNumber()==o2.getNumber()&&o2.isEnd())?-1:1;
			}
		});

		OutputNode outputNode = new OutputNode(-1,-1);
		List<OutputNode> resultList = new ArrayList<OutputNode>();
		for(int i=0;i<gapRangeNodeList.size()-1;i++){
			GapRangeNode n1 = gapRangeNodeList.get(i);
			GapRangeNode n2 = gapRangeNodeList.get(i+1);
			long n = -1;
			long m = -1;
			if(n1.isEnd()){
				n = n1.getNumber()+1;
				outputNode.removeAssetIndex(list.get(n1.getIndex()));
			}else{
				n = n1.getNumber();
				outputNode.addAssetIndex(list.get(n1.getIndex()));
			}
			if(n2.isEnd()){
				m = n2.getNumber();
			}else{
				m = n2.getNumber() - 1;
			}
			if(n <= m && outputNode.getAssetIndexSet().size() > 0){
				OutputNode copyNode = new OutputNode(n,m);
				Iterator<IpRangeAsset> iterator = outputNode.getAssetIndexSet().iterator();
				while(iterator
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值