`
dragonsoar
  • 浏览: 206697 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

java IP库实现

阅读更多

我的官方微博:www.weibo.com/vanwelldotcn

我的官方扣群:102934900

 

    笔者现在主要从事移动互联网相关的一些架构工作,并且负责现在公司内部的平台架构的搭建,那么做移动互联网就一定会涉及到移动终端的IP访问记录,并跟据IP进行定向的广告投放。

        比如现在通地IP可以直接获取IP所对应的省份,那么数据结构应该如下:

        IP | 省份

 

    上面只是笔者模拟的一个表结构,那么具体的IP对应省份,是对终端客户登录时后台DB保存的记录;但是服务器端的IP库,肯定是如下的一个IP段结构

        IP开始段 | IP结束段 | 省份

 

    笔者通过H2内存数据库加载了上面的IP库,然后进行了压力测试;结果发现,在压力大的情况下性格会下降的非常厉害,其实笔记收集到的IP库大小只有40多W行数据而已,50M的数据量。

    在这种情况下,笔者就通过另一种方法实现了IP库段的查询,性能达到了20W+TPS,只是在奔腾双核的机器下面的测试结果,思路如下:

    1.通过TreeMap实现

    2.以IP库的起始段为key(IP库的IP地址转化成long型)

    3.取出比目标IP小,离的最近的IP对应[key值]

    4.然后将查找到的value值和目标IP值进行范围比较

    5.符合则对应此IP段,不符合则未查找到IP库对应的范围地址

 

RangeRow.java
public class RangeRow<T extends Comparable, V> implements Serializable {
private static final long serialVersionUID = -289623726849550889L;
private T begin;
private T end;
private V value;
private Object attachment;

public T getBegin() {
return begin;
}

public void setBegin(T begin) {
this.begin = begin;
}

public T getEnd() {
return end;
}

public void setEnd(T end) {
this.end = end;
}

public V getValue() {
return value;
}

public void setValue(V value) {
this.value = value;
}

public Object getAttachment() {
return attachment;
}

public void setAttachment(Object attachment) {
this.attachment = attachment;
}

}

 

 

IpProvinceRow.java
public class IpProvinceRow extends RangeRow<Long, String> {
private static final long serialVersionUID = 8411106544005822554L;

private String city;

public String getCity() {
return city;
}

public void setCity(String city) {
this.city = city;
}

}

 

 

 

RangeSearchEngine.java
public class RangeSearchEngine<T extends Comparable, V> {
	private TreeMap<T, RangeRow<T, V>> cache = new TreeMap<T, RangeRow<T, V>>();

	@SuppressWarnings("unchecked")
	public V getValue(T key) {
		//
		RangeRow<T, V> row = getRow(key);
		if (row == null) {
			return null;
		}

		//
		T end = row.getEnd();
		if (end == null) {
			return null;
		}
		if (end.compareTo(key) > 0) {
			return row.getValue();
		}

		return null;
	}

	public RangeRow<T, V> getRow(T key) {
		if (key == null) {
			return null;
		}
		//
		Entry<T, RangeRow<T, V>> entry = cache.floorEntry(key);
		if (entry == null || entry.getValue() == null) {
			return null;
		}
		//
		return entry.getValue();
	}

	public void putAll(Map<T, RangeRow<T, V>> map) {
		cache.putAll(map);
	}

	public RangeRow<T, V> put(RangeRow<T, V> row) {
		return cache.put(row.getBegin(), row);
	}

	public RangeRow<T, V> remove(T key) {
		return cache.remove(key);
	}

	public void clear() {
		cache.clear();
	}

	public TreeMap<T, RangeRow<T, V>> getCache() {
		return cache;
	}

	public TreeMap<T, RangeRow<T, V>> setCache(TreeMap<T, RangeRow<T, V>> newCache) {
		if (newCache == null) {
			throw new NullPointerException();
		}
		//
		TreeMap<T, RangeRow<T, V>> before = cache;
		cache = newCache;
		//
		return before;
	}
}
 

 

IpProvinceSearchEngine.java
public class IpProvinceSearchEngine extends RangeSearchEngine<Long, String> {
	public static final String SPLITER = "\\|";
	//
	private Logger logger = LoggerFactory.getLogger(getClass());

	/**
	 * @Title: load
	 * @Description: 载入Ip库文件
	 * @author Administrator
	 * @param dataFile
	 * @throws FileNotFoundException
	 * @throws IOException
	 * @return void 返回类型
	 */
	public void load(String dataFile) throws FileNotFoundException, IOException {
		TreeMap<Long, RangeRow<Long, String>> map = new TreeMap<Long, RangeRow<Long, String>>();
		BufferedReader file = new BufferedReader(new FileReader(dataFile));
		try {
			//
			String content = null;
			while ((content = file.readLine()) != null) {
				String[] parts = content.split(SPLITER);
				if (parts.length < 3) {
					logger.warn("parse line failed, " + content);
					continue;
				}
				//
				try {
					IpProvinceRow row = new IpProvinceRow();
					row.setBegin(Long.valueOf(parts[0]));
					row.setEnd(Long.valueOf(parts[1]));
					row.setValue(parts[2]);
					//
					if (parts.length > 3) {
						row.setCity(parts[3]);
					}
					//
					map.put(row.getBegin(), row);
				} catch (Exception e) {
					logger.warn("parse row failed:" + content);
				}
			}
			//
			setCache(map);
		} finally {
			try {
				file.close();
			} catch (IOException e) {
			}
		}
	}

	/**
	 * @Title: getProvince
	 * @Description: 获取省份信息
	 * @author Administrator
	 * @param @param ip
	 * @param @return 设定文件
	 * @return String 返回类型
	 */
	public String getProvince(String ip) {
		//
		long intIp = convertIpToLong(ip);
		//
		return getValue(intIp);
	}

	/**
	 * @Title: convertIpToLong
	 * @Description: 转换Ip为256进制整数
	 * @author Kolor
	 * @param ip
	 * @return long
	 */
	public static long convertIpToLong(String ip) {
		String[] checkIp = ip.split("\\.", 4);
		long intIp = 0;

		for (int i = 3, j = 0; i >= 0 && j <= 3; i--, j++) {
			intIp += Integer.parseInt(checkIp[j]) * Math.pow(256, i);
		}
		return intIp;
	}

	public static void main(String[] args) throws FileNotFoundException, IOException {
		String file = "C:\\Users\\Administrator.PC-20110801LBXQ\\Desktop\\ip\\ip.data";
		IpProvinceSearchEngine engine = new IpProvinceSearchEngine();
		//
		long beginTime = System.currentTimeMillis();
		engine.load(file);
		long endTime = System.currentTimeMillis();
		System.out.println("load cost " + (endTime - beginTime));
		//
		System.out.println(engine.getProvince("202.101.15.61"));
	}
}

 

附件中是已经收集好的IP库,不能保证最全,但是已经比较全了。:)

希望大家喜欢这个工具类,比较实用;且性能较高,希望有同样数据段查找的数量有限的需求也可以采用类似的方案。

 

分享到:
评论
2 楼 dragonsoar 2013-02-05  
Sunny_kaka 写道

不知道有没有比较好和稳定的查询ip和对应省份关系的web service服务?

有了这个就不和web service了吧?这个多快啊,web service要走网络很慢的了吧
1 楼 Sunny_kaka 2013-02-04  

不知道有没有比较好和稳定的查询ip和对应省份关系的web service服务?

相关推荐

    本程序使用Matlab调用COMSOL进行二元(电容与相对介电常数)数据的生成.zip

    matlab

    操作系统课程设计基于C++实现的操作系统仿真虚拟页式存储管理项目源代码

    操作系统课程设计基于C++实现的操作系统仿真虚拟页式存储管理项目源代码

    西门子S7-1500与V90伺服在定长切断中的应用及优化 - 工业自动化解决方案

    内容概要:本文详细介绍了西门子S7-1500 PLC与V90伺服在定长切断应用中的具体实现方法和技术要点。首先,文章展示了如何利用TIA Portal V16平台配置工艺对象“CuttingAxis”,并解释了关键参数如每转脉冲数、丝杆导程、减速比等的作用。接着,针对可能出现的问题,如轴运行抖动、控制字状态丢失等进行了深入探讨,并提供了相应的解决措施,比如调整前馈参数、修改报文配置等。此外,还分享了一些提高系统性能的小技巧,例如启用动态限制选项、优化速度前馈与位置环配合等。最后,强调了该方案在包装机械和线材加工领域的广泛应用前景及其优势所在。 适合人群:从事工业自动化相关工作的工程师和技术人员,尤其是那些希望深入了解和掌握西门子PLC与伺服系统集成应用的专业人士。 使用场景及目标:适用于需要实现高精度定长切断操作的企业或项目,旨在帮助用户构建稳定可靠的控制系统,确保生产效率和产品质量。 其他说明:文中不仅涵盖了理论知识讲解,还包括大量实际案例分析以及代码示例,便于读者更好地理解和应用所学内容。同时提醒读者关注硬件配置、软件编程、参数调节等多个方面,以达到最佳效果。

    2023年计算机二级Office选择题考前模拟.docx

    2023年计算机二级Office选择题考前模拟.docx

    CMD仿制PYTHON,自己制作,望通过

    目前可以新建目录,具体自己看代码

    基于SpringBoot网上超市(源码+数据库+万字文档)507

    基于SpringBoot网上超市,系统包含两种角色:用户、管理员,系统分为前台和后台两大模块,主要功能如下: 1 管理员功能实现 商品信息管理 管理员可以通过提交商品名称查询商品,并查看该商品的用户评论信息。 用户管理 管理员通过提交用户名来获取用户资料,对有异常情况的用户信息进行修改,并可以详细查看用户资料。 商品评价管理 管理员审核用户对商品的评价,经过审核的评价才会显示,并可以统计商品评价信息。 已支付订单 管理员查看已支付的订单,并逐个进行订单发货。 2 用户功能实现 商品信息 用户可以收藏、立即购买商品,或对商品进行评价,同时将商品添加到购物车。 购物车 用户可以直接下单购买购物车中的商品,或删除购物车中的商品。 确认下单 用户选择地址,查看支付金额信息,以确认订单之前的所有细节。 已支付订单 用户查看已支付的订单,若对购买商品产生后悔,可以申请退款。 二、项目技术 开发语言:Java 数据库:MySQL 项目管理工具:Maven Web应用服务器:Tomcat 前端技术:Vue、 后端技术:SpringBoot框架 三、运行环境 操作系统:Windows、macOS都可以 JDK版本:JDK1.8以上版本都可以 开发工具:IDEA、Ecplise都可以 数据库: MySQL 5.7/8.0版本均可 Tomcat:7.x、8.x、9.x版本均可 Maven:任意版本都可以

    1_媒工十佳决赛RUNDOWN 2.xlsx

    1_媒工十佳决赛RUNDOWN 2.xlsx

    c#联合opencvsharp开发的视觉源码程序包含模板匹配,找线找圆,预处理等功能全部源码,包含图像显示控件,绘制roi

    c#联合opencvsharp开发的视觉源码程序 包含模板匹配,找线找圆,预处理等功能 全部源码,包含图像显示控件,绘制roi

    基于STC89C52单片机的信号发生器20172086102何雨莉_3.zip

    基于STC89C52单片机的信号发生器20172086102何雨莉_3.zip

    2023年西南大学网络与继续教育学院楼宇自动化作业答案.docx

    2023年西南大学网络与继续教育学院楼宇自动化作业答案.docx

    基于SpringBoot与Vue的智慧养老手表管理系统:家庭树、健康数据监控及权限控制

    内容概要:本文详细介绍了基于SpringBoot和Vue构建的智慧养老手表管理系统的关键技术和实现细节。系统主要由家长和养老院管理员两种角色组成,家长可以通过智能手表实时查看老人的健康数据,而管理员则可以进行更全面的数据管理和权限控制。文中重点讨论了家庭树功能的实现,包括使用MyBatis的动态SQL处理复杂的家庭关系查询,以及前端用Vue的el-tree组件展示家庭树结构。健康数据监控方面,系统利用SpringBoot的@Scheduled定时任务生成日报,并通过ECharts进行数据可视化。此外,还涉及了权限控制、加好友功能、熔断机制等多个方面的技术实现。 适合人群:具有一定编程经验的开发者,尤其是熟悉SpringBoot和Vue框架的工程师。 使用场景及目标:适用于开发类似智慧养老系统的项目,旨在提高老年人健康管理的效率和安全性。目标是通过智能手表实时监测老人健康状况,提供及时的健康报告和预警,同时确保系统的稳定性和安全性。 其他说明:文中提到的技术细节对于理解和实现类似的前后端分离架构非常有帮助,特别是关于MySQL 5.7的使用和优化,以及如何处理第三方设备接口的不稳定问题。

    2023年计算机二级资料.doc

    2023年计算机二级资料.doc

    2023年电大数据结构形成性考核册.doc

    2023年电大数据结构形成性考核册.doc

    软考-网络工程师易错100题 2025年

    网络工程师易错100题 2025年

    2023年电子商务技能竞赛方案.doc

    2023年电子商务技能竞赛方案.doc

    2024年大数据软件项目深度研究分析报告.docx

    2024年大数据软件项目深度研究分析报告.docx

    基于Matlab小波变换与凯伦布尔变换的输电线路单相接地故障双端行波测距方法

    内容概要:本文详细介绍了利用Matlab/Simulink构建输电线路单相接地故障测距模型的方法。首先,通过建立110kV输电线路的Simulink模型,采用Bergeron模型作为线路参数。接着,利用小波变换提取故障行波的模极大值点,结合凯伦布尔变换消除工频分量,从而精确计算故障位置。文中提供了详细的代码实现步骤,包括信号预处理、小波分解、模极大值检测以及时间差计算等。此外,还讨论了常见调试经验和避坑指南,如采样率设置、接地电阻限制等。最后,通过多个测试案例验证了模型的有效性和准确性。 适合人群:从事电力系统故障诊断的研究人员和技术人员,尤其是对小波变换和凯伦布尔变换感兴趣的工程师。 使用场景及目标:适用于输电线路单相接地故障的精确定位,旨在提高电力系统的可靠性和维护效率。通过掌握本文提供的方法,技术人员能够快速准确地找到故障点,减少停电时间和维修成本。 其他说明:本文不仅提供了理论解释,还包括具体的代码实现和调试建议,有助于读者更好地理解和应用所学知识。

    含分布式电源的IEEE33节点配电网牛拉法潮流计算解析

    内容概要:本文详细介绍了基于牛拉法的含分布式电源(如风能和太阳能)的IEEE33节点配电网潮流计算程序。首先解释了分布式电源的节点类型转换,将光伏处理为PQ节点,风机处理为PV节点。接着阐述了导纳矩阵的构建方法及其对分布式电源的影响,特别是变压器分接头的处理。然后深入探讨了牛拉法的核心迭代过程,包括功率不平衡量的计算、雅可比矩阵的构建以及修正方程的求解。此外,文章还讨论了风光出力波动的处理方法,并分享了一些常见的陷阱及解决方案,如PV节点振荡、孤岛检测和并行计算优化。最后,通过具体实例展示了程序的运行结果,强调了分布式电源接入位置的重要性。 适合人群:从事电力系统仿真、配电网规划与设计的研究人员和技术人员。 使用场景及目标:适用于研究分布式电源对接入配电网的影响,帮助理解和优化含分布式电源的配电网运行特性,提高潮流计算的准确性。 其他说明:文中提供了详细的代码片段和实践经验,有助于读者更好地理解和应用相关理论和技术。同时,文章指出了实际应用中的一些注意事项,如节点类型切换、变压器变比处理等,使读者能够避免常见错误。

    单片机最小工作系统构建概述.pptx

    单片机最小工作系统构建概述.pptx

    2023年全国计算机二级c语言考试真题详细解答系列一.doc

    2023年全国计算机二级c语言考试真题详细解答系列一.doc

Global site tag (gtag.js) - Google Analytics