读书人

java IP库兑现

发布时间: 2012-07-08 17:43:42 作者: rapoo

java IP库实现

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

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

? ? ? ? IP | 省份

?

? ? 上面只是笔者模拟的一个表结构,那么具体的IP对应省份,是对终端客户登录时后—B保存的记录;但是服务器端的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库,不能保证最全,但是已经比较全了。:)

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

?

读书人网 >互联网

热点推荐