求推荐一个IP解析的库

2020-09-22 23:11发布

求推荐一个IP解析的库

求推荐一个IP解析的库

2条回答
@CcCc
2楼 · 2020-09-22 23:25

求推荐一个IP解析的库

我想吃肉
3楼 · 2020-09-23 09:27

解析主要用到三个类:

(1) IPSeeker.java:通过IP地址查询解析相关信息

(2) SplitAddress.java:IPSeeker解析出的完整信息做进一步切分,划分为0级地址(国家/省)、1级地址(市级)、2级地址(区)、运营商ISP信息。

(3) IPEntity.java:定义的实体字段,包括nation、province、city、region.



-----------------------------------------------------------------------------------------------------------------------------

(1) IPSeeker.java

import java.io.File;import java.io.IOException;import java.io.RandomAccessFile;import java.io.UnsupportedEncodingException;import java.nio.ByteOrder;import java.nio.MappedByteBuffer;import java.nio.channels.FileChannel;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;public class IPSeeker{ private Log log = LogFactory.getLog(IPSeeker.class); //:::::::::::: Class IPLocation :::::::::::::::::::::// public class IPLocation{//:::::::::::: Fields :::::::::::::://  private String country; //完全地址:省/市/区  private String isp;     //使用的网络(运营商ISP)    //:::::::::::: Province ::::::::::::://  public String getCountry() {   return country;  }  public void setCountry(String country) {   this.country = country;  }    public String getIsp(){   if("CZ88.NET".equals(isp)){isp = ""; } return isp;  }    public void setIsp(String isp){   this.isp = isp;  }    //::::::::: Class Constructor ::::::::::::://  public IPLocation(){   isp = "";   country = "";  }    public IPLocation getCopy(){   IPLocation ret = new IPLocation();   ret.country = country;   ret.isp = isp;   return ret;  } }  //:::::::::::: Class IPEntry :::::::::::::::::::::// public class IPEntry{  public String beginIp;  public String endIp;  public String country;  public String isp;    public IPEntry(){   beginIp = endIp = country = isp = "";  }    @Override  public String toString(){   return this.isp+" "+this.country+"IP范围:"+this.beginIp+"-"+this.endIp;  } } //一些固定常量,比如记录长度等 private static final int IP_RECORD_LENGTH = 7;private static final byte isp_FOLLOWED = 0x01;private static final byte NO_isp = 0x2;// 用来做为cache,查询一个ip时首先查看cache,以减少不必要的重复查找private MappedByteBuffer mbb;// 随机文件访问类private RandomAccessFile ipFile;// 内存映射文件private HashMap ipCache;// 起始地区的开始和结束的绝对偏移private int ipBegin, ipEnd;public IPSeeker(File ipFile) throws Exception{     this.ipFile = new RandomAccessFile(ipFile, "r");ipCache = new HashMap();FileChannel fc = this.ipFile.getChannel();mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, ipFile.length());mbb.order(ByteOrder.LITTLE_ENDIAN);ipBegin = readInt(0);ipEnd = readInt(4);if(ipBegin==-1 || ipEnd==-1){         throw new IOException("IP地址信息文件格式有错误,IP显示功能将无法使用");}log.debug("使用IP地址库:"+ipFile.getAbsolutePath());}/**     * 给定一个ip 得到一个 ip地址信息     * @param ip     * @return     */public String getAddress(String ip){     return getCountry(ip) + " " + getIsp(ip);}/**      * 根据IP得到国家名     * @param ip IP的字符串形式     * @return 国家名字符串     */public String getCountry(String ip){     IPLocation cache = getIpLocation(ip);     return cache.getCountry();}/**     * 根据IP得到地区名     * @param ip  IP的字符串形式     * @return  地区名字符串     */public String getIsp(String ip){     IPLocation cache = getIpLocation(ip);return cache.getIsp();}public IPLocation getIpLocation(String ip){     IPLocation ipLocation = null;     try {   if(ipCache.get(ip)!=null){    return ipCache.get(ip);   }   ipLocation = getIPLocation(getIpByteArrayFromString(ip));   if(ipLocation!=null){    ipCache.put(ip, ipLocation);   }  } catch (Exception e) {   log.error(e);  }     if(ipLocation==null){      ipLocation = new IPLocation();ipLocation.setCountry("未知国家");ipLocation.setIsp("未知地区");     }     return ipLocation;}/**     *  给定一个地点的不完全名字,得到一系列包含s子串的IP范围记录     * @param s 地点子串     * @return 包含IPEntry类型的List     */public List getIPEngries(String s){     List ret = new ArrayList();     byte[] b4=new byte[4];int endOffset = ipEnd + 4;for(int offset=ipBegin+4; offset<=endOffset; offset+=IP_RECORD_LENGTH){         //读取结束IP偏移int temp = readInt3(offset);// 如果temp不等于-1,读取IP的地点信息if(temp!=-1){             IPLocation loc = getIPLocation(temp);             // 判断是否这个地点里面包含了s子串,如果包含了,添加这个记录到List中,如果没有,继续if (loc.country.indexOf(s) != -1 || loc.isp.indexOf(s) != -1) {IPEntry entry = new IPEntry();entry.country = loc.country;entry.isp = loc.isp;// 得到起始IPreadIP(offset - 4, b4);entry.beginIp = getIpStringFromBytes(b4);//  得到结束IPreadIP(temp, b4);entry.endIp = getIpStringFromBytes(b4);// 添加该记录ret.add(entry);}}}     return ret;}/**     * 根据ip搜索ip信息文件,得到IPLocation结构,所搜索的ip参数从类成员ip中得到     * @param ip 要查询的IP     * @return  IPLocation结构     */private IPLocation getIPLocation(byte[] ip){     IPLocation info = null;int offset = locateIP(ip);if (offset != -1) {info = getIPLocation(offset);}return info;}//---------以下为内部方法-------------///**     * 读取4个字节     * @param offset     * @return     */private int readInt(int offset) {mbb.position(offset);return mbb.getInt();}private int readInt3(int offset) {mbb.position(offset);return mbb.getInt() & 0x00FFFFFF;}/**     * 从内存映射文件的offset位置得到一个0结尾字符串     * @param offset     * @return     */private String readString(int offset) {try {byte[] buf=new byte[100];mbb.position(offset);int i;for (i = 0, buf[i] = mbb.get(); buf[i] != 0; buf[++i] = mbb.get()) {}if (i != 0) {return getString(buf, 0, i, "GBK");}}catch (IllegalArgumentException e){log.error(e);}return "";}/**     * 从offset位置读取四个字节的ip地址放入ip数组中,读取后的ip为big-endian格式,但是     * 文件中是little-endian形式,将会进行转换     * @param offset     * @param ip     */private void readIP(int offset, byte[] ip) {mbb.position(offset);mbb.get(ip);byte temp = ip[0];ip[0] = ip[3];ip[3] = temp;temp = ip[1];ip[1] = ip[2];ip[2] = temp;}/**     * 把类成员ip和beginIp比较,注意这个beginIp是big-endian的     * @param ip 要查询的IP     * @param beginIp  和被查询IP相比较的IP     * @return 相等返回0,ip大于beginIp则返回1,小于返回-1。     */private int compareIP(byte[] ip, byte[] beginIp) {for (int i = 0; i < 4; i++) {int r = compareByte(ip[i], beginIp[i]);if (r != 0){return r;}}return 0;}/**     * 把两个byte当作无符号数进行比较     * @param b1     * @param b2     * @return 若b1大于b2则返回1,相等返回0,小于返回-1     */private int compareByte(byte b1, byte b2) {if ((b1 & 0xFF) > (b2 & 0xFF)){ //比较是否大于return 1;}else if((b1^b2)==0){ //判断是否相等return 0;}else{return -1;}}/**     * 这个方法将根据ip的内容,定位到包含这个ip国家地区的记录处,返回一个绝对偏移     * 方法使用二分法查找。     * @param ip 要查询的IP     * @return 如果找到了,返回结束IP的偏移,如果没有找到,返回-1     */private int locateIP(byte[] ip) {int m = 0;int r;byte[] b4=new byte[4];// 比较第一个ip项readIP(ipBegin, b4);r = compareIP(ip, b4);if (r == 0) {return ipBegin;} else if (r < 0) {return -1;}//  开始二分搜索for (int i = ipBegin, j = ipEnd; i < j;) {m = getMiddleOffset(i, j);readIP(m, b4);r = compareIP(ip, b4);// log.debug(Utils.getIpStringFromBytes(b));if (r > 0) {i = m;} else if (r < 0) {if (m == j) {j -= IP_RECORD_LENGTH;m = j;} else {j = m;}} else {return readInt3(m + 4);}}// 如果循环结束了,那么i和j必定是相等的,这个记录为最可能的记录,但是并非// 肯定就是,还要检查一下,如果是,就返回结束地址区的绝对偏移m = readInt3(m + 4);readIP(m, b4);r = compareIP(ip, b4);if (r <= 0) {return m;} else {return -1;}}/**     * 得到begin偏移和end偏移中间位置记录的偏移     * @param begin     * @param end     * @return     */private int getMiddleOffset(int begin, int end) {int records = (end - begin) / IP_RECORD_LENGTH;records >>= 1;if (records == 0) {records = 1;}return begin + records * IP_RECORD_LENGTH;}/**     * @param offset     * @return     */private IPLocation getIPLocation(int offset) {IPLocation loc = new IPLocation();// 跳过4字节ipmbb.position(offset + 4);// 跳过4字节ipbyte b = mbb.get();if (b == isp_FOLLOWED) {// 读取国家偏移int countryOffset = readInt3();// 跳转至偏移处mbb.position(countryOffset);// 再检查一次标志字节,因为这个时候这个地方仍然可能是个重定向b = mbb.get();if (b == NO_isp) {loc.country = readString(readInt3());mbb.position(countryOffset + 4);} else {loc.country = readString(countryOffset);}// 读取地区标志loc.isp = readisp(mbb.position());} else if (b == NO_isp) {loc.country = readString(readInt3());loc.isp = readisp(offset + 8);} else {loc.country = readString(mbb.position() - 1);loc.isp = readisp(mbb.position());}return loc;}/**     * @param offset     * @return     */private String readisp(int offset) {mbb.position(offset);byte b = mbb.get();if (b == 0x01 || b == 0x02){int ispOffset = readInt3();if(ispOffset == 0){return "未知地区";}else{return readString(ispOffset);}}else{return readString(offset);}}/**     * 从内存映射文件的当前位置开始的3个字节读取一个int     * @return     */private int readInt3(){return mbb.getInt() & 0x00FFFFFF;}/**     *  从ip的字符串形式得到字节数组形式:字符串序列化为二进制文件     * @param ip 字符串形式的ip     * @return 字节数组形式的ip     */private static byte[] getIpByteArrayFromString(String ip) throws Exception{byte[] ret = new byte[4];java.util.StringTokenizer st = new java.util.StringTokenizer(ip, ".");try{ret[0] = (byte)(Integer.parseInt(st.nextToken()) & 0xFF);ret[1] = (byte)(Integer.parseInt(st.nextToken()) & 0xFF);ret[2] = (byte)(Integer.parseInt(st.nextToken()) & 0xFF);ret[3] = (byte)(Integer.parseInt(st.nextToken()) & 0xFF);}catch(Exception e){throw e;}return ret;}/**     * 根据某种编码方式将字节数组转换成字符串     * @param b 字节数组     * @param offset 要转换的起始位置     * @param len 要转换的长度     * @param encoding  编码方式     * @return 如果encoding不支持,返回一个缺省编码的字符串     */private static String getString(byte[] b, int offset, int len, String encoding) {try {return new String(b, offset, len, encoding);}catch(UnsupportedEncodingException e){return new String(b, offset, len);}}/**     * @param ip ip的字节数组形式     * @return 字符串形式的ip     */private static String getIpStringFromBytes(byte[] ip) {StringBuffer sb = new StringBuffer();sb.append(ip[0] & 0xFF);sb.append('.');sb.append(ip[1] & 0xFF);sb.append('.');sb.append(ip[2] & 0xFF);sb.append('.');sb.append(ip[3] & 0xFF);return sb.toString();}}


(2)SplitAddress.java


import java.io.File;/** * @Note 地址切分____将全域地址切分为:  0级地址:国家或省 *            1级地址:市 *            2级地址:区 *  *    调用时直接调用IPseeker类:eg.  ipseeker.getAddress("xxx.xxx.xxx.xxx"); *                                    ipseeker.getCountry("xxx.xxx.xxx.xxx"); *                                    ipseeker.getIsp("xxx.xxx.xxx.xxx"); *       由于ipentity.nation,province,city,region是作的切分,故 ipentity.getNation()等没有输入参数,调用直接输出 *                ipentity.getNation(); *                ipentity.getProvince(); *                ipentity.getCity(); *                     ipentity.getRegion(); *       测试ip:202.112.110.0 -----北京市 北京邮电大学 *         27.184.95.146 ------河北省石家庄市 电信 *              219.136.134.157 -----广东省广州市越秀区 电信ADSL *              59.45.1.151 --------辽宁省盘锦市双台子区 胜星网吧(辽河北路与城北路交汇) *              61.128.101.255 -----新疆乌鲁木齐市 电信 *              220.182.50.226 -----西藏拉萨市 波斯湾网络会所(宇拓路30号) *              210.136.134.157 -----日本  CZ88.NET *              207.46.13.93 -----美国  Microsoft公司 *              27.122.12.0 ------香港 智通(Pacswitch)环球电讯 *               */ public class SplitAddress { public static void main(String[] args){  try {   IPSeeker ipseeker = new IPSeeker(new File("e:/aleiye/data/QQWry.dat"));   IPEntity ipentity = new IPEntity();   String ipaddress = "27.122.12.0";   SplitAddress splitaddress = new SplitAddress();   splitaddress.SplitAddressAction(ipaddress, ipseeker, ipentity); //切分获得多级地址      System.out.println("完整ip信息:"+ipseeker.getAddress(ipaddress));   System.out.println("完全地址:省/市/区:"+ipseeker.getCountry(ipaddress));   System.out.println("nation:"+ipentity.getNation());   System.out.println("province:"+ipentity.getProvince());   System.out.println("city:"+ipentity.getCity());   System.out.println("region:"+ipentity.getRegion());   System.out.println("使用的网络(运营商ISP):"+ipseeker.getIsp(ipaddress));  } catch (Exception e) {   e.printStackTrace();  }   }  public void SplitAddressAction(String ipaddress, IPSeeker ipseeker, IPEntity ipentity){  try {      String alladdress = ipseeker.getCountry(ipaddress);    String[] part;   //全国省市里唯一没有"市"字样的只有这4个省,直接作逗号","切分   if(alladdress.startsWith("新疆")){    ipentity.setProvince("新疆");    alladdress = alladdress.replace("新疆", "新疆,");   }   else if(alladdress.startsWith("西藏")){    ipentity.setProvince("西藏");    alladdress = alladdress.replace("西藏", "西藏,");   }   else if(alladdress.startsWith("内蒙古")){    ipentity.setProvince("内蒙古");    alladdress = alladdress.replace("内蒙古", "内蒙古,");   }   else if(alladdress.startsWith("宁夏")){    ipentity.setProvince("宁夏");    alladdress = alladdress.replace("宁夏", "宁夏,");   }   alladdress = alladdress.replaceAll("省", "省,").replaceAll("市", "市,"); //最多切成3段:辽宁省,盘锦市,双台子区;   part = alladdress.split(",");      if(part.length==1){    //只有1级地址    ipentity.setNation(part[0]);    ipentity.setProvince(part[0]);   }   else if(part.length==2){    //有2级地址    ipentity.setProvince(part[0]);    ipentity.setCity(part[1]);   }   else if(part.length==3){    //有3级地址    ipentity.setProvince(part[0]);    ipentity.setCity(part[1]);    ipentity.setRegion(part[2]);   }     } catch (Exception e) {   e.printStackTrace();  } } }



(3) IPEntity.java


public class IPEntity { String nation;   //国家:0级地址 String province; //省:0级地址 String city;     //市:1级地址 String region;   //区:2级地址  public String getNation() {  return nation; } public void setNation(String nation) {  this.nation = nation; } public String getProvince() {  return province; } public void setProvince(String province) {  this.province = province; } public String getCity() {  return city; } public void setCity(String city) {  this.city = city; } public String getRegion() {  return region; } public void setRegion(String region) {  this.region = region; }  public IPEntity(){   }}


相关问题推荐

  • 什么是大数据时代?2021-01-13 21:23
    回答 100

    大数据(big data)一词越来越多地被提及,人们用它来描述和定义信息爆炸时代产生的海量数据,而这个海量数据的时代则被称为大数据时代。随着云时代的来临,大数据(Big data)也吸引了越来越多的关注。大数据(Big data)通常用来形容一个公司创造的大量非结...

  • 回答 84

    Java和大数据的关系:Java是计算机的一门编程语言;可以用来做很多工作,大数据开发属于其中一种;大数据属于互联网方向,就像现在建立在大数据基础上的AI方向一样,他两不是一个同类,但是属于包含和被包含的关系;Java可以用来做大数据工作,大数据开发或者...

  • 回答 52
    已采纳

    学完大数据可以从事很多工作,比如说:hadoop 研发工程师、大数据研发工程师、大数据分析工程师、数据库工程师、hadoop运维工程师、大数据运维工程师、java大数据工程师、spark工程师等等都是我们可以从事的工作岗位!不同的岗位,所具备的技术知识也是不一样...

  • 回答 29

    简言之,大数据是指大数据集,这些数据集经过计算分析可以用于揭示某个方面相关的模式和趋势。大数据技术的战略意义不在于掌握庞大的数据信息,而在于对这些含有意义的数据进行专业化处理。大数据的特点:数据量大、数据种类多、 要求实时性强、数据所蕴藏的...

  • 回答 14

    tail -f的时候,发现一个奇怪的现象,首先 我在一个窗口中 tail -f test.txt 然后在另一个窗口中用vim编辑这个文件,增加了几行字符,并保存,这个时候发现第一个窗口中并没有变化,没有将最新的内容显示出来。tail -F,重复上面的实验过程, 发现这次有变化了...

  • 回答 18

    您好针对您的问题,做出以下回答,希望有所帮助!1、大数据行业还是有非常大的人才需求的,对于就业也有不同的岗位可选,比如大数据工程师,大数据运维,大数据架构师,大数据分析师等等,就业难就难在能否找到适合的工作,能否与你的能力和就业预期匹配。2、...

  • 回答 17

    最小的基本单位是Byte应该没多少人不知道吧,下面先按顺序给出所有单位:Byte、KB、MB、GB、TB、PB、EB、ZB、YB、DB、NB,按照进率1024(2的十次方)计算:1Byte = 8 Bit1 KB = 1,024 Bytes 1 MB = 1,024 KB = 1,048,576 Bytes 1 GB = 1,024 MB = 1,048,576...

  • 回答 33

    大数据的定义。大数据,又称巨量资料,指的是所涉及的数据资料量规模巨大到无法通过人脑甚至主流软件工具,在合理时间内达到撷取、管理、处理、并整理成为帮助企业经营决策更积极目的的资讯。大数据是对大量、动态、能持续的数据,通过运用新系统、新工具、新...

  • 回答 5

    MySQL是一种关系型数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。MySQL的版本:针对不同的用户,MySQL分为两种不同的版本:MySQL Community Server社区版本,免费,但是Mysql不提供...

  • mysql安装步骤mysql 2022-05-07 18:01
    回答 2

    mysql安装需要先使用yum安装mysql数据库的软件包 ;然后启动数据库服务并运行mysql_secure_installation去除安全隐患,最后登录数据库,便可完成安装

  • 回答 5

    1.查看所有数据库showdatabases;2.查看当前使用的数据库selectdatabase();3.查看数据库使用端口showvariableslike&#39;port&#39;;4.查看数据库编码showvariableslike‘%char%’;character_set_client 为客户端编码方式; character_set_connection 为建立连接...

  • 回答 5

    CREATE TABLE IF NOT EXISTS `runoob_tbl`(    `runoob_id` INT UNSIGNED AUTO_INCREMENT,    `runoob_title` VARCHAR(100) NOT NULL,    `runoob_author` VARCHAR(40) NOT NULL,    `submission_date` DATE,    PRI...

  • 回答 9

    学习多久,我觉得看你基础情况。1、如果原来什么语言也没有学过,也没有基础,那我觉得最基础的要先选择一种语言来学习,是VB,C..,pascal,看个人的喜好,一般情况下,选择C语言来学习。2、如果是有过语言的学习,我看应该一个星期差不多,因为语言的理念互通...

  • 回答 7

    添加语句 INSERT插入语句:INSERT INTO 表名 VALUES (‘xx’,‘xx’)不指定插入的列INSERT INTO table_name VALUES (值1, 值2,…)指定插入的列INSERT INTO table_name (列1, 列2,…) VALUES (值1, 值2,…)查询插入语句: INSERT INTO 插入表 SELECT * FROM 查...

  • 回答 5

    看你什么岗位吧。如果是后端,只会CRUD。应该是可以找到实习的,不过公司应该不会太好。如果是数据库开发岗位,那这应该是不会找到的。

  • 回答 7

    查找数据列 SELECT column1, column2, … FROM table_name; SELECT column_name(s) FROM table_name 

没有解决我的问题,去提问