精华内容
下载资源
问答
  • 准确率99.9%的ip地址定位库,0.0x毫秒级查询,数据库文件大小只有1.5M,提供了java,php,c,python,nodejs,golang查询绑定和Binary,B树,内存三种查询算法,妈妈再也不用担心我的ip地址定位
  • 今天小编推荐一款Ip地址库,准确率99.9%离线IP地址定位库,0.0x毫秒级查询,这个库数据库只有数MB,提供了java,php,c,python,nodejs,golang,c#等查询绑定和Binary,B树,内存三种查询算法。 开源协议   使用 A

      大家好,我是为广大程序员兄弟操碎了心的小编,每天推荐一个小工具/源码,装满你的收藏夹,每天分享一个小技巧,让你轻松节省开发效率,实现不加班不熬夜不掉头发,是我的目标!

      咱们程序员开发任何系统,基本上都需要查询IP地址,比如操作日志、登录IP等等。今天小编推荐一款Ip地址库,准确率99.9%的离线IP地址定位库,0.0x毫秒级查询,这个库数据库只有数MB,提供了java,php,c,python,nodejs,golang,c#等查询绑定和Binary,B树,内存三种查询算法。

    开源协议

      使用 Apache-2.0 开源许可协议

    链接地址

      公众号【Github导航站】回复关键词【ip2】获取git地址

    99.9%准确率

      数据聚合了一些知名ip到地名查询提供商的数据,这些是他们官方的的准确率,经测试着实比经典的纯真IP定位准确一些。
      本库数据聚合自以下服务商的开放API或者数据(升级程序每秒请求次数2到4次):

    • 01, >80%, 淘宝IP地址库
    • 02, ≈10%, GeoIP
    • 03, ≈2%, 纯真IP库
      **备注:**如果上述开放API或者数据都不给开放数据时,该库将停止数据的更新服务。

    标准化的数据格式

      每条ip数据段都固定了格式:

    _城市Id|国家|区域|省份|城市|ISP_
    

      只有中国的数据精确到了城市,其他国家有部分数据只能定位到国家,后前的选项全部是0,已经包含了全部你能查到的大大小小的国家(请忽略前面的城市Id,个人项目需求)。

    体积小

      包含了全部的IP,生成的数据库文件只有几MB,最小的版本只有1.5MB,随着数据的详细度增加数据库的大小也慢慢增大,目前还没超过8MB。

    查询速度快

      全部的查询客户端单次查询都在0.x毫秒级别,内置了三种查询算法

    1. memory算法:整个数据库全部载入内存,单次查询都在0.1x毫秒内,C语言的客户端单次查询在0.00x毫秒级别。
    2. binary算法:基于二分查找,不需要载入内存,单次查询在0.x毫秒级别。
    3. b-tree算法:基于btree算法,不需要载入内存,单词查询在0.x毫秒级别,比binary算法更快。

    任何客户端b-tree都比binary算法快,当然memory算法固然是最快的!

    多查询客户端的支持

    已经集成的客户端有:java、C#、php、c、python、nodejs、php扩展(php5和php7)、golang、rust、lua、lua_c, nginx。

    image-20210321114217969

    结尾

      本期就分享到这里,我是小编南风吹,专注分享好玩有趣、新奇、实用的开源项目及开发者工具、学习资源!希望能与大家共同学习交流,欢迎关注我的公众号**【Github导航站】**。

    展开全文
  • 准确率99.9%的ip地址定位库,0.0x毫秒级查询,数据库文件大小只有1.5M,提供了java,php,c,python,nodejs,golang,c#查询绑定和Binary,B树,内存三种查询算法,妈妈再也不用担心我的ip地址定位
  • ip地址定位

    2016-08-22 11:02:00
    准确率99.9%的ip地址定位库,0.0x毫秒级查询,数据库文件大小只有1.5M,提供了java, php, c, python, nodejs查询绑定和Binary,B树,内存三种查询算法,妈妈再也不用担心我的ip地址定位! 1.2.1更新内容如下: 1,...

    ip2region 1.2.1 发布了,新增 Python 内存查询+数据文件更新。

    准确率99.9%的ip地址定位库,0.0x毫秒级查询,数据库文件大小只有1.5M,提供了java, php, c, python, nodejs查询绑定和Binary,B树,内存三种查询算法,妈妈再也不用担心我的ip地址定位!

        1.2.1更新内容如下:

        1,python查询客户端增加内存查询模式。

        2,数据更新至2016/07/12版本,届时ip2region.db文件大小1.6M。

    版本仓库地址:

    http://git.oschina.net/lionsoul/ip2region
    https://github.com/lionsoul2014/ip2region

    转载于:https://www.cnblogs.com/zl0372/p/ip2region.html

    展开全文
  • 之前在《使用阿里云的ip地址查询服务-购买ip地址查询服务》介绍了阿里云付费版的ip地址查询,可以定位ip所在的地理位置,费用也不高。大家可以试试。不过阿里云还有一个免费版的ip地址查询服务,象征性地做一下购买...

    转载请注明出处:http://blog.csdn.net/dongdong9223/article/details/54691857
    本文出自【我是干勾鱼的博客

    之前在《使用阿里云的ip地址查询服务-购买ip地址查询服务》介绍了阿里云付费版的ip地址查询,可以定位ip所在的地理位置,费用也不高。大家可以试试。

    不过阿里云还有一个免费版的ip地址查询服务,象征性地做一下购买(不花钱)就可以使用,如图所示:

    这里写图片描述

    调用方式与付费版是一样的。当然既然是免费版,就避免费的稍差一点。付费版的号称:

    提供全国数千万IP地址查询,包含省、市、运营商等信息,每周更新,对比IP138、淘宝、百度等数据,保证权威准确。

    而免费版的则只是:

    根据用户提供的IP地址,快速查询出该IP地址的地理相关信息,包括国家、省、市和运营商。

    会有一定的准确度差异的。

    展开全文
  • 用户进入到网站的首页后,默认城市应该是用户本地的城市信息,例如:北京,网站就要根据你的IP地址的信息,查询数据,获取北京部分的数据,呵呵,当然可能描述的不是很清楚,但是可以理解成,通过IP地址定位地理...

          做电子商务网站的时候,网站的头部一般都有显示是哪个城市的,用户进入到网站的首页后,默认城市应该是用户本地的城市信息,例如:北京,网站就要根据你的IP地址的信息,查询数据,获取北京部分的数据,呵呵,当然我可能描述的不是很清楚,但是可以理解成,通过IP地址定位地理信息就行。

         在做网站的时候,参考网上一下相关的文章和说明,上班偷闲之际整理了IP定位的部分,方便以后使用的时候查询,具体参考如下:

     

    1. 我用到了QQWry.dat,当然首先是引入该文件。

     

    2. 封装通过IP获取的信息,包括国家,地区等。

    package com.lzb.ip;
    /**
     * 
     * 功能描述:封装IP地址信息POJO
     * 			一条IP范围记录,不仅包括国家和区域,也包括起始IP和结束IP
     *
     * @author  Administrator
     *
     * <p>修改历史:(修改人,修改时间,修改原因/内容)</p>
     */
    public class IPEntry {
    	
    	// 起始IP
        public String beginIp;
        // 结束IP
        public String endIp;
        // 归属国家
        public String country;
        // 归属地区
        public String area;
        
        /**
         * 
         * 构造函数:清空信息
         *
         */
        public IPEntry() {
        	
            beginIp = ""; 
            endIp = "";
            country = "";
            area = "";
        }
    }

     3. 通过获取的IP信息,查询出所在地的信息,其实就是一个读取QQWry.dat匹配获取相关的信息。

    package com.lzb.ip;
    
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.RandomAccessFile;
    import java.net.URL;
    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 java.util.Map;
    import org.apache.log4j.Level;
    
    import com.lzb.io.ReadProUtil;
    /**
     * 
     * 功能描述: 用来读取QQwry.dat文件,确定Ip
     *
     * @author  Administrator
     *
     * <p>修改历史:(修改人,修改时间,修改原因/内容)</p>
     */
    public class IPSeeker {
    	
    	//纯真IP数据库名
    	private String IP_FILE = "QQWry.Dat";
    	//保存的文件夹
    	private String INSTALL_DIR = null;	
    	
    	// 一些固定常量,比如记录长度等等
    	private static final int IP_RECORD_LENGTH = 7;
    	private static final byte REDIRECT_MODE_1 = 0x01;
    	private static final byte REDIRECT_MODE_2 = 0x02;
    	
    	// 用来做为cache,查询一个ip时首先查看cache,以减少不必要的重复查找
    	private Map<String, IPLocation> ipCache;
    	// 随机文件访问类
    	private RandomAccessFile ipFile;
    	// 内存映射文件
    	private MappedByteBuffer mbb;
    	// 起始地区的开始和结束的绝对偏移
    	private long ipBegin, ipEnd;
    	// 为提高效率而采用的临时变量
    	private IPLocation loc;
    	private byte[] buf;
    	private byte[] b4;
    	private byte[] b3;
    	
    	/**
    	 * 
    	 * 构造函数:初始化
    	 *
    	 */
    	public IPSeeker()  {
    		
    		// 获取文件的路径和名称
    		StringBuffer sb = new StringBuffer();
    		URL url = IPSeeker.class.getResource("");
    		sb.append(url.getPath() + this.IP_FILE);		
    		this.IP_FILE = sb.toString();;
    		ipCache = new HashMap<String, IPLocation>();
    		loc = new IPLocation();
    		buf = new byte[100];
    		b4 = new byte[4];
    		b3 = new byte[3];
    		
    		try {
    			
    			ipFile = new RandomAccessFile(IP_FILE, "r");
    			
    		} catch (FileNotFoundException e) {
    			// 如果找不到这个文件,再尝试再当前目录下搜索,这次全部改用小写文件名
    			// 因为有些系统可能区分大小写导致找不到ip地址信息文件
    			String filename = new File(IP_FILE).getName().toLowerCase();
    			File[] files = new File(INSTALL_DIR).listFiles();
    			for(int i = 0; i < files.length; i++) {
    				if(files[i].isFile()) {
    					if(files[i].getName().toLowerCase().equals(filename)) {
    						try {
    							ipFile = new RandomAccessFile(files[i], "r");
    						} catch (FileNotFoundException e1) {
    							LogFactory.log("IP地址信息文件没有找到,IP显示功能将无法使用",Level.ERROR,e1);
    							ipFile = null;
    						}
    						break;
    					}
    				}
    			}
    		} 
    		// 如果打开文件成功,读取文件头信息
    		if(ipFile != null) {
    			try {
    				ipBegin = readLong4(0);
    				ipEnd = readLong4(4);
    				if(ipBegin == -1 || ipEnd == -1) {
    					ipFile.close();
    					ipFile = null;
    				}			
    			} catch (IOException e) {
    				LogFactory.log("IP地址信息文件格式有错误,IP显示功能将无法使用",Level.ERROR,e);
    				ipFile = null;
    			}			
    		}
    	}
    	
    	/**
    	 * 
    	 * 功能描述:给定一个地点的不完全名字,得到一系列包含s子串的IP范围记录
    	 *
    	 * @author  Administrator
    	 * <p>创建日期 :2012-3-14 上午9:53:22</p>
    	 *
    	 * @param s
    	 * 			地点子串
    	 * @return
    	 * 			包含IPEntry类型的List
    	 *
    	 * <p>修改历史 :(修改人,修改时间,修改原因/内容)</p>
    	 */
    	public List getIPEntriesDebug(String s) {
    		
    	    List<IPEntry> ret = new ArrayList<IPEntry>();
    	    long endOffset = ipEnd + 4;
    	    for(long offset = ipBegin + 4; offset <= endOffset; offset += IP_RECORD_LENGTH) {
    	        // 读取结束IP偏移
    	        long temp = readLong3(offset);
    	        // 如果temp不等于-1,读取IP的地点信息
    	        if(temp != -1) {
    	            IPLocation ipLoc = getIPLocation(temp);
    	            // 判断是否这个地点里面包含了s子串,如果包含了,添加这个记录到List中,如果没有,继续
    	            if(ipLoc.getCountry().indexOf(s) != -1 || ipLoc.getArea().indexOf(s) != -1) {
    	                IPEntry entry = new IPEntry();
    	                entry.country = ipLoc.getCountry();
    	                entry.area = ipLoc.getArea();
    	                // 得到起始IP
    	    	        readIP(offset - 4, b4);
    	                entry.beginIp = Util.getIpStringFromBytes(b4);
    	                // 得到结束IP
    	                readIP(temp, b4);
    	                entry.endIp = Util.getIpStringFromBytes(b4);
    	                // 添加该记录
    	                ret.add(entry);
    	            }
    	        }
    	    }
    	    return ret;
    	}
    	
    	/**
    	 * 
    	 * 功能描述:获取Ip所在地区信息
    	 *
    	 * @author  Administrator
    	 * <p>创建日期 :2012-3-14 上午9:54:15</p>
    	 *
    	 * @param ip
    	 * 			IP地址
    	 * @return
    	 *
    	 * <p>修改历史 :(修改人,修改时间,修改原因/内容)</p>
    	 */
    	public IPLocation getIPLocation(String ip) {
    		
    		IPLocation location = new IPLocation();
    		location.setArea(this.getArea(ip));
    		location.setCountry(this.getCountry(ip));
    		return location;
    	}
    	
    	/**
    	 * 
    	 * 功能描述:给定一个地点的不完全名字,得到一系列包含s子串的IP范围记录
    	 *
    	 * @author  Administrator
    	 * <p>创建日期 :2012-3-14 上午9:55:22</p>
    	 *
    	 * @param s
    	 * 			地点子串
    	 * @return
    	 * 			包含IPEntry类型的List
    	 *
    	 * <p>修改历史 :(修改人,修改时间,修改原因/内容)</p>
    	 */
    	public List<IPEntry> getIPEntries(String s) {
    		
    	    List<IPEntry> ret = new ArrayList<IPEntry>();
    	    try {
    	        // 映射IP信息文件到内存中
    	        if(mbb == null) {
    			    FileChannel fc = ipFile.getChannel();
    	            mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, ipFile.length());
    	            mbb.order(ByteOrder.LITTLE_ENDIAN);	            
    	        }
                
    		    int endOffset = (int)ipEnd;
                for(int offset = (int)ipBegin + 4; offset <= endOffset; offset += IP_RECORD_LENGTH) {
                    int temp = readInt3(offset);
                    if(temp != -1) {
        	            IPLocation ipLoc = getIPLocation(temp);
        	            // 判断是否这个地点里面包含了s子串,如果包含了,添加这个记录到List中,如果没有,继续
        	            if(ipLoc.getCountry().indexOf(s) != -1 || ipLoc.getArea().indexOf(s) != -1) {
        	                IPEntry entry = new IPEntry();
        	                entry.country = ipLoc.getCountry();
        	                entry.area = ipLoc.getArea();
        	                // 得到起始IP
        	    	        readIP(offset - 4, b4);
        	                entry.beginIp = Util.getIpStringFromBytes(b4);
        	                // 得到结束IP
        	                readIP(temp, b4);
        	                entry.endIp = Util.getIpStringFromBytes(b4);
        	                // 添加该记录
        	                ret.add(entry);
        	            }
                    }
                }           
            } catch (IOException e) {
                LogFactory.log("",Level.ERROR,e);
            }
            return ret;
    	}
    
    	/**
    	 * 
    	 * 功能描述:从内存映射文件的offset位置开始的3个字节读取一个int
    	 *
    	 * @author  Administrator
    	 * <p>创建日期 :2012-3-14 上午9:57:26</p>
    	 *
    	 * @param offset
    	 * @return
    	 *
    	 * <p>修改历史 :(修改人,修改时间,修改原因/内容)</p>
    	 */
    	private int readInt3(int offset) {
    		
    	    mbb.position(offset);
    	    return mbb.getInt() & 0x00FFFFFF;
    	}
    
    	/**
    	 * 
    	 * 功能描述: 从内存映射文件的当前位置开始的3个字节读取一个int
    	 *
    	 * @author  Administrator
    	 * <p>创建日期 :2012-3-14 上午9:57:47</p>
    	 *
    	 * @return
    	 *
    	 * <p>修改历史 :(修改人,修改时间,修改原因/内容)</p>
    	 */
    	private int readInt3() {
    		
    	    return mbb.getInt() & 0x00FFFFFF;
    	}
    	
    	/**
    	 * 
    	 * 功能描述:根据IP得到国家名
    	 *
    	 * @author  Administrator
    	 * <p>创建日期 :2012-3-14 上午9:58:01</p>
    	 *
    	 * @param ip
    	 * 			ip的字节数组形式
    	 * @return
    	 * 			国家名字符串
    	 *
    	 * <p>修改历史 :(修改人,修改时间,修改原因/内容)</p>
    	 */
    	public String getCountry(byte[] ip) {
    		
    		// 检查ip地址文件是否正常
    		if(ipFile == null) 
    			return Message.bad_ip_file;
    		// 保存ip,转换ip字节数组为字符串形式
    		String ipStr = Util.getIpStringFromBytes(ip);
    		// 先检查cache中是否已经包含有这个ip的结果,没有再搜索文件
    		if(ipCache.containsKey(ipStr)) {
    			IPLocation ipLoc = ipCache.get(ipStr);
    			return ipLoc.getCountry();
    		} else {
    			IPLocation ipLoc = getIPLocation(ip);
    			ipCache.put(ipStr, ipLoc.getCopy());
    			return ipLoc.getCountry();
    		}
    	}
    
    	/**
    	 * 
    	 * 功能描述:国家名字符串
    	 *
    	 * @author  Administrator
    	 * <p>创建日期 :2012-3-14 上午9:58:32</p>
    	 *
    	 * @param ip
    	 * 			IP的字符串形式
    	 * @return
    	 * 			国家名字符串
    	 *
    	 * <p>修改历史 :(修改人,修改时间,修改原因/内容)</p>
    	 */
    	public String getCountry(String ip) {
    		
    	    return getCountry(Util.getIpByteArrayFromString(ip));
    	}
    	
    	/**
    	 * 
    	 * 功能描述:国家名字符串
    	 *
    	 * @author  Administrator
    	 * <p>创建日期 :2012-3-14 上午9:59:11</p>
    	 *
    	 * @param ip
    	 * 			ip的字节数组形式
    	 * @return
    	 * 			ip的字节数组形式
    	 *
    	 * <p>修改历史 :(修改人,修改时间,修改原因/内容)</p>
    	 */
    	public String getArea(byte[] ip) {
    		// 检查ip地址文件是否正常
    		if(ipFile == null) 
    			return Message.bad_ip_file;
    		// 保存ip,转换ip字节数组为字符串形式
    		String ipStr = Util.getIpStringFromBytes(ip);
    		// 先检查cache中是否已经包含有这个ip的结果,没有再搜索文件
    		if(ipCache.containsKey(ipStr)) {
    			IPLocation ipLoc = ipCache.get(ipStr);
    			return ipLoc.getArea();
    		} else {
    			IPLocation ipLoc = getIPLocation(ip);
    			ipCache.put(ipStr, ipLoc.getCopy());
    			return ipLoc.getArea();
    		}
    	}
    	
    	/**
    	 * 
    	 * 功能描述:根据IP得到地区名
    	 *
    	 * @author  Administrator
    	 * <p>创建日期 :2012-3-14 上午9:59:46</p>
    	 *
    	 * @param ip
    	 * 			ip IP的字符串形式
    	 * @return
    	 * 			地区名字符串
    	 *
    	 * <p>修改历史 :(修改人,修改时间,修改原因/内容)</p>
    	 */
    	public String getArea(String ip) {
    		
    	    return getArea(Util.getIpByteArrayFromString(ip));
    	}
    	
    	/**
    	 * 根据ip搜索ip信息文件,得到IPLocation结构,所搜索的ip参数从类成员ip中得到
    	 * @param ip 要查询的IP
    	 * @return IPLocation结构
    	 */
    	private IPLocation getIPLocation(byte[] ip) {
    		IPLocation info = null;
    		long offset = locateIP(ip);
    		if(offset != -1)
    			info = getIPLocation(offset);
    		if(info == null) {
    			info = new IPLocation();
    			info.setCountry (  Message.unknown_country);
    			info.setArea(Message.unknown_area);
    		}
    		return info;
    	}	
    
    	/**
    	 * 从offset位置读取4个字节为一个long,因为java为big-endian格式,所以没办法
    	 * 用了这么一个函数来做转换
    	 * @param offset
    	 * @return 读取的long值,返回-1表示读取文件失败
    	 */
    	private long readLong4(long offset) {
    		
    		long ret = 0;
    		try {
    			ipFile.seek(offset);
    			ret |= (ipFile.readByte() & 0xFF);
    			ret |= ((ipFile.readByte() << 8) & 0xFF00);
    			ret |= ((ipFile.readByte() << 16) & 0xFF0000);
    			ret |= ((ipFile.readByte() << 24) & 0xFF000000);
    			return ret;
    		} catch (IOException e) {
    			return -1;
    		}
    	}
    
    	/**
    	 * 从offset位置读取3个字节为一个long,因为java为big-endian格式,所以没办法
    	 * 用了这么一个函数来做转换
    	 * @param offset 整数的起始偏移
    	 * @return 读取的long值,返回-1表示读取文件失败
    	 */
    	private long readLong3(long offset) {
    		long ret = 0;
    		try {
    			ipFile.seek(offset);
    			ipFile.readFully(b3);
    			ret |= (b3[0] & 0xFF);
    			ret |= ((b3[1] << 8) & 0xFF00);
    			ret |= ((b3[2] << 16) & 0xFF0000);
    			return ret;
    		} catch (IOException e) {
    			return -1;
    		}
    	}	
    	
    	/**
    	 * 从当前位置读取3个字节转换成long
    	 * @return 读取的long值,返回-1表示读取文件失败
    	 */
    	private long readLong3() {
    		long ret = 0;
    		try {
    			ipFile.readFully(b3);
    			ret |= (b3[0] & 0xFF);
    			ret |= ((b3[1] << 8) & 0xFF00);
    			ret |= ((b3[2] << 16) & 0xFF0000);
    			return ret;
    		} catch (IOException e) {
    			return -1;
    		}
    	}
      
    	/**
    	 * 从offset位置读取四个字节的ip地址放入ip数组中,读取后的ip为big-endian格式,但是
    	 * 文件中是little-endian形式,将会进行转换
    	 * @param offset
    	 * @param ip
    	 */
    	private void readIP(long offset, byte[] ip) {
    		try {
    			ipFile.seek(offset);
    			ipFile.readFully(ip);
    			byte temp = ip[0];
    			ip[0] = ip[3];
    			ip[3] = temp;
    			temp = ip[1];
    			ip[1] = ip[2];
    			ip[2] = temp;
    		} catch (IOException e) {
    		    LogFactory.log("",Level.ERROR,e);
    		}
    	}
    	
    	/**
    	 * 从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 long locateIP(byte[] ip) {
    		long m = 0;
    		int r;
    		// 比较第一个ip项
    		readIP(ipBegin, b4);
    		r = compareIP(ip, b4);
    		if(r == 0) return ipBegin;
    		else if(r < 0) return -1;
    		// 开始二分搜索
    		for(long 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 readLong3(m + 4);
    		}
    		// 如果循环结束了,那么i和j必定是相等的,这个记录为最可能的记录,但是并非
    		//     肯定就是,还要检查一下,如果是,就返回结束地址区的绝对偏移
    		m = readLong3(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 long getMiddleOffset(long begin, long end) {
    		long records = (end - begin) / IP_RECORD_LENGTH;
    		records >>= 1;
    		if(records == 0) records = 1;
    		return begin + records * IP_RECORD_LENGTH;
    	}
    	
    	/**
    	 * 给定一个ip国家地区记录的偏移,返回一个IPLocation结构
    	 * @param offset 国家记录的起始偏移
    	 * @return IPLocation对象
    	 */
    	private IPLocation getIPLocation(long offset) {
    		try {
    			// 跳过4字节ip
    			ipFile.seek(offset + 4);
    			// 读取第一个字节判断是否标志字节
    			byte b = ipFile.readByte();
    			if(b == REDIRECT_MODE_1) {
    				// 读取国家偏移
    				long countryOffset = readLong3();
    				// 跳转至偏移处
    				ipFile.seek(countryOffset);
    				// 再检查一次标志字节,因为这个时候这个地方仍然可能是个重定向
    				b = ipFile.readByte();
    				if(b == REDIRECT_MODE_2) {
    					loc.setCountry (  readString(readLong3()));
    					ipFile.seek(countryOffset + 4);
    				} else
    					loc.setCountry ( readString(countryOffset));
    				// 读取地区标志
    				loc.setArea( readArea(ipFile.getFilePointer()));
    			} else if(b == REDIRECT_MODE_2) {
    				loc.setCountry ( readString(readLong3()));
    				loc.setArea( readArea(offset + 8));
    			} else {
    				loc.setCountry (  readString(ipFile.getFilePointer() - 1));
    				loc.setArea( readArea(ipFile.getFilePointer()));
    			}
    			return loc;
    		} catch (IOException e) {
    			return null;
    		}
    	}	
    	
    	/**
    	 * 给定一个ip国家地区记录的偏移,返回一个IPLocation结构,此方法应用与内存映射文件方式
    	 * @param offset 国家记录的起始偏移
    	 * @return IPLocation对象
    	 */
    	private IPLocation getIPLocation(int offset) {
    		// 跳过4字节ip
    	    mbb.position(offset + 4);
    		// 读取第一个字节判断是否标志字节
    		byte b = mbb.get();
    		if(b == REDIRECT_MODE_1) {
    			// 读取国家偏移
    			int countryOffset = readInt3();
    			// 跳转至偏移处
    			mbb.position(countryOffset);
    			// 再检查一次标志字节,因为这个时候这个地方仍然可能是个重定向
    			b = mbb.get();
    			if(b == REDIRECT_MODE_2) {
    				loc.setCountry (  readString(readInt3()));
    				mbb.position(countryOffset + 4);
    			} else
    				loc.setCountry (  readString(countryOffset));
    			// 读取地区标志
    			loc.setArea(readArea(mbb.position()));
    		} else if(b == REDIRECT_MODE_2) {
    			loc.setCountry ( readString(readInt3()));
    			loc.setArea(readArea(offset + 8));
    		} else {
    			loc.setCountry (  readString(mbb.position() - 1));
    			loc.setArea(readArea(mbb.position()));
    		}
    		return loc;
    	}
    	
    	/**
    	 * 从offset偏移开始解析后面的字节,读出一个地区名
    	 * @param offset 地区记录的起始偏移
    	 * @return 地区名字符串
    	 * @throws IOException
    	 */
    	private String readArea(long offset) throws IOException {
    		ipFile.seek(offset);
    		byte b = ipFile.readByte();
    		if(b == REDIRECT_MODE_1 || b == REDIRECT_MODE_2) {
    			long areaOffset = readLong3(offset + 1);
    			if(areaOffset == 0)
    				return Message.unknown_area;
    			else
    				return readString(areaOffset);
    		} else
    			return readString(offset);
    	}
    	
    	/**
    	 * @param offset 地区记录的起始偏移
    	 * @return 地区名字符串
    	 */
    	private String readArea(int offset) {
    		mbb.position(offset);
    		byte b = mbb.get();
    		if(b == REDIRECT_MODE_1 || b == REDIRECT_MODE_2) {
    			int areaOffset = readInt3();
    			if(areaOffset == 0)
    				return Message.unknown_area;
    			else
    				return readString(areaOffset);
    		} else
    			return readString(offset);
    	}
    	
    	/**
    	 * 从offset偏移处读取一个以0结束的字符串
    	 * @param offset 字符串起始偏移
    	 * @return 读取的字符串,出错返回空字符串
    	 */
    	private String readString(long offset) {
    		try {
    			ipFile.seek(offset);
    			int i;
    			for(i = 0, buf[i] = ipFile.readByte(); buf[i] != 0; buf[++i] = ipFile.readByte());
    			if(i != 0) 
    			    return Util.getString(buf, 0, i, "GBK");
    		} catch (IOException e) {			
    		    LogFactory.log("",Level.ERROR,e);
    		}
    		return "";
    	}
    	
    	/**
    	 * 从内存映射文件的offset位置得到一个0结尾字符串
    	 * @param offset 字符串起始偏移
    	 * @return 读取的字符串,出错返回空字符串
    	 */
    	private String readString(int offset) {
    	    try {
    			mbb.position(offset);
    			int i;
    			for(i = 0, buf[i] = mbb.get(); buf[i] != 0; buf[++i] = mbb.get());
    			if(i != 0) 
    			    return Util.getString(buf, 0, i, "GBK");       
    	    } catch (IllegalArgumentException e) {
    	        LogFactory.log("",Level.ERROR,e);
    	    }
    	    return "";	 
    	}
    }

     4. 返回相关的国家,区域信息

    package com.lzb.ip;
    /**
     * 
     * 功能描述:用来封装ip相关信息,目前只有两个字段,ip所在的国家和地区
     *
     * @author  Administrator
     *
     * <p>修改历史:(修改人,修改时间,修改原因/内容)</p>
     */
    public class IPLocation {
    	
    	private String country;
    	private String area;
    	
    	/**
    	 * 
    	 * 构造函数:
    	 *
    	 */
    	public IPLocation() {
    		
    	    country = "";
    	    area = "";
    	}
    	
    	public IPLocation getCopy() {
    		
    	    IPLocation ret = new IPLocation();
    	    ret.country = country;
    	    ret.area = area;
    	    return ret;
    	}
    
    	public String getCountry() {
    		return country;
    	}
    
    	public void setCountry(String country) {
    		this.country = country;
    	}
    
    	public String getArea() {
    		return area;
    	}
    
    	public void setArea(String area) {
    		
    		//如果为局域网,纯真IP地址库的地区会显示CZ88.NET,这里把它去掉
    		if(area.trim().equals("CZ88.NET")){
    			this.area="本机或本网络";
    		}else{
    			this.area = area;
    		}
    	}
    }

     5. 日志工厂

    package com.lzb.ip;
    
    import org.apache.log4j.Level;
    import org.apache.log4j.Logger;
    /**
     * 
     * 功能描述:日志工厂
     *
     * @author  Administrator
     *
     * <p>修改历史:(修改人,修改时间,修改原因/内容)</p>
     */
    public class LogFactory {
    	
    	private static final Logger logger;
    	
    	static {
    		logger = Logger.getLogger("stdout");
    		logger.setLevel(Level.DEBUG);
    	}
    
    	public static void log(String info, Level level, Throwable ex) {
    		logger.log(level, info, ex);
    	}
    	
    	public static Level  getLogLevel(){
    		return logger.getLevel();
    	}
    
    }

     6. 提示的日志信息

    package com.lzb.ip;
    /**
     * 
     * 功能描述:提示的信息
     *
     * @author  Administrator
     *
     * <p>修改历史:(修改人,修改时间,修改原因/内容)</p>
     */
    public interface Message {
    	
    	static String bad_ip_file = "IP地址库文件错误";
    	static String unknown_country = "未知国家";
    	static String unknown_area = "未知地区";
    	
    }

     7. 转换工具类,字符串,数组

    package com.lzb.ip;
    
    import java.io.UnsupportedEncodingException;
    import java.util.StringTokenizer;
    import org.apache.log4j.Level;
    /**
     * 
     * 功能描述:转换工具类
     *
     * @author  Administrator
     *
     * <p>修改历史:(修改人,修改时间,修改原因/内容)</p>
     */
    public class Util {
    	
    	private static StringBuilder sb = new StringBuilder();
    
    	/**
    	 * 
    	 * 功能描述:从ip的字符串形式得到字节数组形式
    	 *
    	 * @author  Administrator
    	 * <p>创建日期 :2012-3-14 上午10:04:02</p>
    	 *
    	 * @param ip
    	 * 			字符串形式的ip
    	 * @return
    	 * 			字节数组形式的ip
    	 *
    	 * <p>修改历史 :(修改人,修改时间,修改原因/内容)</p>
    	 */
        public static byte[] getIpByteArrayFromString(String ip) {
            
        	byte[] ret = new byte[4];
            StringTokenizer st = new 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) {
              LogFactory.log("从ip的字符串形式得到字节数组形式报错", Level.ERROR, e);
            }
            return ret;
        }
        
        /**
         * 
         * 功能描述 IP数组转换成字符串
         *
         * @author  Administrator
         * <p>创建日期 :2012-3-14 上午10:04:51</p>
         *
         * @param ip
         * 			ip的字节数组形式
         * @return
         * 			字符串形式的ip
         *
         * <p>修改历史 :(修改人,修改时间,修改原因/内容)</p>
         */
        public static String getIpStringFromBytes(byte[] ip) {
    	    
        	sb.delete(0, sb.length());
        	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();
        }
        
        /**
         * 
         * 功能描述:根据某种编码方式将字节数组转换成字符串
         *
         * @author  Administrator
         * <p>创建日期 :2012-3-14 上午10:05:50</p>
         *
         * @param b
         * 			字节数组
         * @param offset
         * 			要转换的起始位置
         * @param len
         * 			要转换的长度
         * @param encoding
         * 			编码方式
         * @return
         * 			如果encoding不支持,返回一个缺省编码的字符串
         *
         * <p>修改历史 :(修改人,修改时间,修改原因/内容)</p>
         */
        public 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);
            }
        }
    }

     

    8. 验证测试方法(Junit)

    package com.lzb.ip;
    
    import java.net.InetAddress;
    import java.net.NetworkInterface;
    import java.net.SocketException;
    import java.net.UnknownHostException;
    import java.util.Enumeration;
    
    import org.junit.Test;
    
    import junit.framework.TestCase;
    /**
     * 
     * 功能描述:测试
     *
     * @author  Administrator
     *
     * <p>修改历史:(修改人,修改时间,修改原因/内容)</p>
     */
    public class IPtest extends TestCase {
    	
    	/**
    	 * 
    	 * 功能描述:测试IP归属地
    	 *
    	 * @author  Administrator
    	 * <p>创建日期 :2012-3-14 上午10:28:48</p>
    	 *
    	 *
    	 * <p>修改历史 :(修改人,修改时间,修改原因/内容)</p>
    	 */
    	@Test
    	public void testIp(){
    		
    //		InetAddress addr = null;
    //		try {
    //			addr = InetAddress.getLocalHost();
    //		} catch (UnknownHostException e) {
    //			e.printStackTrace();
    //		}
    //		String ipStr = addr.getHostAddress().toString();//获得本机IP
    //		String addressStr = addr.getHostName().toString();//获得本机名称
    //		
    //		System.out.println("本机IP地址: " + ipStr + " 本机名称: " + addressStr);
    		
    		String ipStr = this.getRealIp();
    		System.out.println("本机IP地址: " + ipStr);
    		
    		//指定纯真数据库的文件名,所在文件夹
    		IPSeeker ip=new IPSeeker();
    		//测试IP 58.20.43.13
    		System.out.println(ip.getIPLocation(ipStr).getCountry()+":"+ip.getIPLocation(ipStr).getArea());
    	}
    	
    	/**
    	 * 
    	 * 功能描述:获取本地真实的IP地址
    	 *
    	 * @author  Administrator
    	 * <p>创建日期 :2012-3-14 上午10:23:01</p>
    	 *
    	 * @return
    	 * @throws SocketException
    	 *
    	 * <p>修改历史 :(修改人,修改时间,修改原因/内容)</p>
    	 */
    	public static String getRealIp() {
    		
    		String localip = null;// 本地IP,如果没有配置外网IP则返回它
    		String netip = null;// 外网IP
    
    		Enumeration<NetworkInterface> netInterfaces = null;
    		try {
    			netInterfaces = NetworkInterface.getNetworkInterfaces();
    		} catch (SocketException e) {
    			e.printStackTrace();
    		}
    		
    		InetAddress ip = null;
    		boolean finded = false;// 是否找到外网IP
    		while (netInterfaces.hasMoreElements() && !finded) {
    			
    			NetworkInterface ni = netInterfaces.nextElement();
    			Enumeration<InetAddress> address = ni.getInetAddresses();
    			while (address.hasMoreElements()) {
    				ip = address.nextElement();
    				if (!ip.isSiteLocalAddress() && !ip.isLoopbackAddress() && ip.getHostAddress().indexOf(":") == -1) {// 外网IP
    					netip = ip.getHostAddress();
    					finded = true;
    					break;
    				} else if (ip.isSiteLocalAddress() && !ip.isLoopbackAddress() && ip.getHostAddress().indexOf(":") == -1) {// 内网IP
    					localip = ip.getHostAddress();
    				}
    			}
    		}
    	
    		if (netip != null && !"".equals(netip)) {
    			return netip;
    		} else {
    			return localip;
    		}
    	}
    }

    运行结果:

    本机IP地址: 10.10.1.24
    局域网:对方和您在同一内部网

      

     

    注意,需要使用还需要下载QQWry.dat文件,google,百度一下很多,我的工程目录

     

    展开全文
  • 实现步骤 1、先查看本机IP地址 2、安装工具Wireshark ...打开CMD,输入命令ipconfig查看自己的IP地址 知道自己的ip地址后打开Wireshark。选择自己电脑上网的方式,我的是WIFI就选WLAN Ctrl+F设置数据筛选:...
  • openGPS.cn - 基于ip的定位技术分享,高精度IP定位

    万次阅读 热门讨论 2016-10-03 12:21:52
    利用业余时间自己做了个网站,集成了几个第三方数据源,对比IP地址查询的功能: 普通IP定位:https://www.opengps.cn/Data/IP/IPSearch.aspx 高精度IP定位-1:https://www.opengps.cn/Data/IP/IPHighAccuracy.aspx...
  • 最近使用java写爬虫的时候,遇到查询所爬取地址的ip信息,通过百度搜索发现...通过查看InetSocketAddress源码不难发现其实InetSocketAddress也是基于InetAddress来定位ip地址的 所以选择直接使用InetAddress实现 ...
  • 由于离线查询ip需要全球IP的分布数据,所以直接选择了一个免费离线查询ip的数据包, GeoLite2-City.mmdb MMDB即Maxmind DB,是一个设计用于存储IPv4和IPv6数据信息数据库,mmdb文件是一个二进制格式文件,它...
  • 点击右侧的聊天按钮,经常出现手机在北京结果定位到天津的问题,或者广州的用户定位到深圳的问题,如果是苹果手机访问的话则正常定位程序中是通过获取用户ip然后跟ip淘宝地址库中的ip进行比对确定客户的所属城市...
  • 根据IP地址获取地理位置

    万次阅读 2018-09-23 17:19:37
    注意:这里指的是公网的IP地址,而不是局域网的IP地址,之前因为是在学校,所以获取的本机IP是经过校园再分配的地址,不是公网的IP地址,导致定位失败。所以我们需要用到IP查询接口,之前用的是:http://ip.c...
  • ip地址与地理位置对应表,我的 IP 地址是多少?在线查询 IP 地址或域名的国家和城市信息,在地图上定位 IP 地址的地理位置。
  • 前言: 前段时间听过了纯真ip数据库,只知道是一个qqwry....换一种方式,才用将qqwry.dat中的ip数据导入mysql数据库中,通过数据库的查询来提供ip位置查询功能。 gitee代码地址: 纯真ip库服务搭建 数据准备 首先
  • 一、手机App定位看来有三种方法:1.通过Android自带API:...通过外部接口获取到外网IP,再通过百度API或者聚合数据API得出地址1、Android自带API,它有三种定位方式可以通过GPS,网络和WIFI定位。1.1步骤:...
  • 用户进入到网站的首页后,默认城市应该是用户本地的城市信息,例如:北京,网站就要根据你的IP地址的信息,查询数据,获取北京部分的数据,呵呵,当然可能描述的不是很清楚,但是可以理解成,通过IP地址定位地理...
  • 通过js获取本地IP地址

    万次阅读 2018-09-10 11:23:20
    最近在做pc项目,需要根据用户的IP地址定位城市。IP地址需要通过js获取: 网上有很多查询接口可以获取到IP,这里用的是搜狐的: http://pv.sohu.com/cityjson?ie=utf-8 在浏览器中,直接输入这个地址,就可以...
  • 根据IP获取城市-Java调用“ip2region”地址库实例-妈妈再也不用担心我的ip地址定位啦 ip2region 准确率99.9%的ip地址定位库,0.0x毫秒级查询,数据库文件大小只有1.5M,提供了java,php,c,python,nodejs,golang...
  • 在这里,使用第三方定位服务:淘宝的Ip地址库 只需要调用淘宝的Ip地址库就能查询到所在地区.   淘宝Ip地址库链接: http://ip.aliyun.com/instructions.html   在上图中可以看见,我们需要调用的API地址和...
  • 用户进入到网站的首页后,默认城市应该是用户本地的城市信息,例如:北京,网站就要根据你的IP地址的信息,查询数据,获取北京部分的数据,呵呵,当然可能描述的不是很清楚,但是可以理解成,通过IP地址定位地理...
  • 怎么样使用Redis来存储和查询ip数据

    千次阅读 2014-09-21 11:11:07
    今天我的朋友佛手给我打了个电话,他们网站的业务要根据客户的ip地址快速定位客户的地理位置。网上已经有一大堆类似的ip地址库可以用,但问题是这些地址库的数据表结构大多如下所示
  • IP

    2010-04-15 14:47:00
    IP地址查询是基于IP的寻址规则和分配标准对Internet上的某一台计算机惟一的IP地址进行追踪和定位的查询,基于此查询结果可以进行各种后续操作,包括对不良者实施制裁等。下面简要说明一下IP地址查询的相关知识。...

空空如也

空空如也

1 2 3 4 5 ... 7
收藏数 139
精华内容 55
关键字:

我的ip地址查询定位