有做過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庫文件結構應該是怎樣的呢?
如圖所示:
可以看到,我們的結構是這樣的:
IP數據包的結構已經定下來了,後面就是一步步處理了。
1. 逐條讀取IP文本文件內容,IP轉為32位有符號整數(自定義的ip2long),地區文字分析獲取到最終地區
a. IP文本文件每行的規則為:前15字節為IP起始地址,後15字節為IP結束地址,最後為地區文字描述。
b. IP轉為32位有符號整數只占4字節,且解決了PHP函數ip2long在32位與64位系統下值不同的問題,新的函數如下:
ip2Long32( = ('l', ('l', ( [1
當然,你也可以自己開發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
表現還不錯。呵呵
結束了,有什麼更好的方式可以一起討論下,謝謝~