使用ruby解析纯真IP库(qqwry.dat)
来源:互联网 发布:js密码和确认密码校验 编辑:程序博客网 时间:2024/04/29 08:02
在写一个地区相关的节能时,需要用到根据IP判断地区的功能,就想着找一个能够解析IP到地址的库。找了一下资料,国内用的比较多的IP库是早年就开始流行到现在的纯真IP库(QQrwy.dat),至于用ruby来解析纯真IP库的,则没找到几个,文章是不少,不过引用的几乎都是同样的代码,那个是比较早的ruby版本了,在1.9.2下跑的话,会有问题,我小改了一下,发现还是会有些问题,于是索性自己写一个吧。
要解析纯真IP库,对于该库的数据结构是必须要了解的,不多说,网上几乎唯一的纯真数据格式的说明就是这篇了 纯真IP数据库格式解析
格式并不算太复杂,主要是要注意偏移。纯真IP库的字符编码是GB2312的,而Windows下的命令行窗口也是GB2312编码,所以就不用转编码了。不过我是在linux下写的,所以默认编码用的是utf8,这也算是大势所趋么(也提供了GB编码的取得方式)。
代码如下,如果看过IP库格式的话,配上代码注释,应该是比较容易就懂的。
试了一下,查询1000次用时大概200毫秒左右
require 'iconv'class IpSearch def initialize(file='qqwry.dat') filename = file @file = File.open(filename,"r") @index_first,@index_last = @file.read(8).unpack('L2') @index_total = (@index_last - @index_first)/7 + 1 @location = {} end #把IP转换为长整形 def ip2long(ip) long = 0 ip.split(/\./).each_with_index do |b, i| long += b.to_i << 8*(3-i) end long end #读取偏移值 def read_offset(position) @file.seek position chars = @file.read(3).unpack('C3') (chars[2]<<16) + (chars[1]<<8) + chars[0] end #读取记录中的4字节作为一个long值 def read_long(position) @file.seek position @file.read(4).unpack('L')[0] end #读取模式信息,1和2为正常,其他值异常 #position:字符串偏移量 def read_mode(position) @file.seek position #前4位为IP值 @file.read(1).unpack('C')[0] end #根据IP在索引中查找具体位置 def find_str_offset(ip_long) offset_min,offset_max = @index_first,@index_last while offset_min <= offset_max offset_mid = offset_min + (offset_max - offset_min) / 14*7 mid = read_long(offset_mid) if ip_long < mid offset_max = offset_mid - 7 elsif ip_long == mid return read_offset(offset_mid+4) else offset_min = offset_mid + 7 end end return read_offset(offset_max+4) end #读取字符串 def read_str(position) @file.seek position str = [] while c = @file.getc break if str.size > 60 #地址不会太长,防止有异常数据 break if c == "\0" #地址字符串以\0结尾 str << c end str.join '' end #根据IP查找地址 def find_ip_location(ip) offset = find_str_offset(ip2long(ip))#读取具体数据在记录区的偏移 @location = {} case read_mode(offset+4) when 1 str_offset = read_offset(offset+4+1) #读取字符串存储位置偏移(4是IP值,1是模式) if read_mode(str_offset)==2 then country_offset = read_offset(str_offset+1) @location[:country] = read_str country_offset @location[:area] = read_area(str_offset+4) else @location[:country] = read_str str_offset @location[:area] = read_area(@file.pos) end when 2 str_offset = read_offset(offset+4+1) #读取字符串存储位置偏移(4是IP值,1是模式) @location[:country] = read_str(str_offset) @location[:area] = read_area(offset+8) else @location[:country] = read_str(offset) @location[:area] = read_str(@file.pos) end @location end #读取记录中的地址信息 def read_area(position) mode = read_mode(position) if mode==1 || mode==2 offset = read_offset(position+1) return '' if offset==0 return read_str(offset) else return read_str(position) end end #取得国家,UTF8编码 def country Iconv.iconv('UTF-8//IGNORE','GB2312//IGNORE',@location[:country]) end #取得地区,UTF8编码 def area Iconv.iconv('UTF-8//IGNORE','GB2312//IGNORE',@location[:area]) end #取得国家,GB2312编码 def country_gb @location[:country] end #取得地区,GB2312编码 def area_gb @location[:area] endend#************************以下测试代码*****************time_start = Time.nowlist = %w[66.249.71.153 202.8.15.255.2 61.157.175.233 58.19.176.201 61.178.12.170 61.191.187.113 121.14.133.169 58.222.234.230 202.198.184.136 121.12.116.58 203.191.148.55]is = IpSearch.new100.times do |i| list.each do |ip| is.find_ip_location(ip) #puts is.country #puts is.area #puts '-'*50 endendputs "total time:#{Time.now-time_start}"
0 0
- 使用ruby解析纯真IP库(qqwry.dat)
- QQWry.Dat纯真IP数据库解析
- 纯真IP数据库QQWry.dat格式详解
- 纯真IP数据库QQWry.dat格式详解
- PHP获取IP地址所在地信息(使用纯真IP数据库qqwry.dat)
- 用Python脚本查询纯真IP库QQWry.dat(Demon修改版)
- java读取纯真IP数据库QQwry.dat的源代码
- java读取纯真IP数据库qqwry.dat的源代码
- c++ 解析纯真IP数据库qqwry
- 纯真IP数据库(qqwry.dat)转换成最新的IP数据库格式(ipwry.dat)
- 使用QQWry.dat获取ip地址
- 读取纯真IP数据库QQwry.dat的java版程序报数组越界异常问题
- 读取纯真IP数据库QQwry.dat的java版程序报数组越界异常问题 .22
- 通过qqwry.dat解析IP地址的动态链接库(C++源码)
- PHP 直接从 QQWry.dat 解析IP地址的程序
- 利用hadoop+hive+python+qqwry.dat批量解析ip物理地址
- 使用QQWry.Dat根据IP查询归属地
- Java使用qqwry.dat根据IP地质获取城市信息
- Cocos2d-x 常用语句
- 安卓带点击效果的圆角button
- 世界坐标转UGUI屏幕坐标
- Linux Advance--标准I/O的效率
- 合入mpls的情况-netlink失灵了
- 使用ruby解析纯真IP库(qqwry.dat)
- 在dwz系统框架下添加的简单网站便签
- ASI和AFN简单对比
- Android apk动态加载机制的研究(二):资源加载和activity生命周期管理
- Android数据库
- 基于容器云的微服务架构实践
- SqlServer查询所有数据表
- JNDI and EJB
- 配置Play开发环境以及创建Demo