>  기사  >  백엔드 개발  >  制作一个自己的二进制IP库文件_PHP教程

制作一个自己的二进制IP库文件_PHP教程

WBOY
WBOY원래의
2016-07-20 11:14:141201검색

一、前言

有做过IP归属地查询功能的朋友应该都有听说过纯真IP库,纯真IP库查询类似这样:

若你仅需要根据IP搜索出用户的归属地文字然后显示出来,只要按照该IP库的规则进行二分查找并显示就OK了。(格式详解)

但如果你需要根据IP获取归属地文字描述,然后进一步与自己已有的行政地区数据表关联起来该如何处理呢?

粗看这两种应该是都可以实现,但是效率呢?都很差!特别是面对并发稍高的应用,这两种方式都经不起考验。

为什么不根据纯真IP库(其他IP库也可以)的数据与自己的地区数据关联起来,用自己的地区ID来代替纯真IP库的地区描述,最后制作一个自己的二进制IP库文件呢?

让我们进入正题,看看如何根据纯真IP库数据制作一个自己的二进制IP库文件。

 注:本文只说明大致思路,没有详细代码,谢谢

二、准备工作

我们需要准备好两部分的数据:

  1. 纯真IP库解压后的txt文件。

    纯真IP库下载后会有个ip.exe工具,使用上面的解压即可生成。

    生成的数据如图1-1,我这个版本有大概444290条。

    

                图1-1

 

  2. 自己的国家省市级联数据表。

    这个网上应该比较多,自己进行导入,表结构类似(area_id, area_level, area_name, area_pid),分别代表地区ID,地区等级,地区名称,父地区ID。

    当然你也可以自己使用不同的结构,不影响我们这次的处理。

 

三、过程 

  数据已经有了,现在来规划下我们需要生成的IP库的机构。

  从标题中就知道,我们需要生成的IP库是二进制的数据包,而不是普通文本文件,那么我们的IP库文件结构应该是怎样的呢?

  如图所示:

  

  可以看到,我们的结构是这样的:

    • 头部。位于文件的前8个字节。前4字节存放32位整数,值为数据部分的开始在文件中的位置;后4字节也存放32位整数,值为数据部分的结束在文件中的位置
    • 主体数据部分。由N个固定结构体组成,每个结构体12字节,为一条IP范围数据(ip_start, ip_end, area_code)。结构体的三个部分也分别为32位有符号整数,各4字节。(area_code若是量小的话也可以使用1个字符)

  

  IP数据包的结构已经定下来了,后面就是一步步处理了。

    1. 逐条读取IP文本文件内容,IP转为32位有符号整数(自定义的ip2long),地区文字分析获取到最终地区

      a. IP文本文件每行的规则为:前15字节为IP起始地址,后15字节为IP结束地址,最后为地区文字描述。

      b. IP转为32位有符号整数只占4字节,且解决了PHP函数ip2long在32位与64位系统下值不同的问题,新的函数如下:

<span function</span> ip2Long32(<span $ip</span><span ) {
    </span><span $ip</span> = <span unpack</span>('l', <span pack</span>('l', <span ip2long</span>(<span $ip</span><span )));
    </span><span return</span> <span $ip</span>[1<span ];
} </span><span //</span><span  end func</span>

      当然,你也可以自己开发PHP扩展,详见这边:http://www.cnblogs.com/iblaze/archive/2013/06/02/3112603.html

      c. 地区需要获取到各级别地区名称(包括省、市、县、区等,这边国外只保留国家),正则如图:

      

  

    2. 将获取到的地区信息转为地区ID

      这部分处理我不太好描述,因为可能每个人用到的地区都不一样,但是大致原理就是先根据最低级地区名称去查找ID(看实际情况,有可能要去掉市、县之类),若是没有则查找上一级,如此循环,直到获取到地区ID。

      若是没有查找到地区ID,则都归入未知。

    3. 压缩,压缩后的文件约为5.08M

      压缩规则如图,format中的值对应pack中的类型:

      

      这边有个地方必须提示下,由于IP转为有符号32位整数,则128.0.0.0以后的IP都会为负数,所以需要判断负数,并放入我们IP库的前面去,毕竟是使用二分查找,需要为有序数据。

      

    4. 查找IP,使用二分查找,44W条数据最多只需要搜索19次,类似如下:

      

    

    4. 单个测试,看起来速度还可以

      

    5. 简单压测看效果

         a. ab压测,使用本机的ab

      b. 测试脚本在linux测试机(普通PC机)

      c. 压测脚本如下:

      

      d. 压测语句: ab -n 10000 -c 50 http://192.168.206.71/ipdata.php?type=php

      

      表现还不错。呵呵

      


 

  结束了,有什么更好的方式可以一起讨论下,谢谢~

      

www.bkjia.comtruehttp://www.bkjia.com/PHPjc/440306.htmlTechArticle一、前言 有做过IP归属地查询功能的朋友应该都有听说过纯真IP库,纯真IP库查询类似这样: 若你仅需要根据IP搜索出用户的归属地文字然后...
성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.