日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

IP 属地功能实现

發布時間:2023/12/14 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 IP 属地功能实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

ttpServletRequest 獲取 IP

下面,我就來講講,Java 中是如何獲取 IP 屬地的,主要分為以下幾步:

  • 通過 HttpServletRequest 對象,獲取用戶的?「IP」?地址

  • 通過 IP 地址,獲取對應的省份、城市

首先需要寫一個 IP 獲取的工具類,因為每一次用戶的 Request 請求,都會攜帶上請求的 IP 地址放到請求頭中。

import javax.servlet.http.HttpServletRequest; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.UnknownHostException;/*** 常用獲取客戶端信息的工具*/ public class NetworkUtil {/*** 獲取ip地址*/public static String getIpAddress(HttpServletRequest request) {String ip = request.getHeader("x-forwarded-for");if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("Proxy-Client-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("WL-Proxy-Client-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("HTTP_CLIENT_IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("HTTP_X_FORWARDED_FOR");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getRemoteAddr();}// 本機訪問if ("localhost".equalsIgnoreCase(ip) || "127.0.0.1".equalsIgnoreCase(ip) || "0:0:0:0:0:0:0:1".equalsIgnoreCase(ip)){// 根據網卡取本機配置的IPInetAddress inet;try {inet = InetAddress.getLocalHost();ip = inet.getHostAddress();} catch (UnknownHostException e) {e.printStackTrace();}}// 對于通過多個代理的情況,第一個IP為客戶端真實IP,多個IP按照','分割if (null != ip && ip.length() > 15) {if (ip.indexOf(",") > 15) {ip = ip.substring(0, ip.indexOf(","));}}return ip;}/*** 獲取mac地址*/public static String getMacAddress() throws Exception {// 取mac地址byte[] macAddressBytes = NetworkInterface.getByInetAddress(InetAddress.getLocalHost()).getHardwareAddress();// 下面代碼是把mac地址拼裝成StringStringBuilder sb = new StringBuilder();for (int i = 0; i < macAddressBytes.length; i++) {if (i != 0) {sb.append("-");}// mac[i] & 0xFF 是為了把byte轉化為正整數String s = Integer.toHexString(macAddressBytes[i] & 0xFF);sb.append(s.length() == 1 ? 0 + s : s);}return sb.toString().trim().toUpperCase();}}

通過此方法,從請求 Header 中獲取到用戶的 IP 地址。

之前我在做的項目中,也有獲取 IP 地址歸屬地省份、城市的需求,用的是:淘寶 IP 庫,地址:

淘寶IP地址庫

?

?taobao 的 ip 庫下線了,再見 ip.taobao,全網顯示 IP 歸屬地。

?

Ip2region

下面,給大家介紹下之前在 Github 沖浪時發現的今天的主角:Ip2region 開源項目。

github 地址:

GitHub - lionsoul2014/ip2region: Ip2region (2.0 - xdb) is a offline IP address manager framework and locator, support billions of data segments, ten microsecond searching performance. xdb engine implementation for many programming languages

目前最新已更新到了 v2.0 版本,ip2region v2.0 是一個離線 IP 地址定位庫和 IP 定位數據管理框架,10 微秒級別的查詢效率,準提供了眾多主流編程語言的 xdb 數據生成和查詢客戶端實現。

①99.9% 準確率

數據聚合了一些知名 ip 到地名查詢提供商的數據,這些是他們官方的的準確率,經測試著實比經典的純真 IP 定位準確一些。

ip2region 的數據聚合自以下服務商的開放 API 或者數據(升級程序每秒請求次數 2 到 4 次):

  • 01,>80%,淘寶IP地址庫,http://ip.taobao.com/%5C

  • 02,≈10%,GeoIP,https://geoip.com/%5C

  • 03,≈2%,純真 IP 庫,http://www.cz88.net/%5C

備注:如果上述開放 API 或者數據都不給開放數據時 ip2region 將停止數據的更新服務。

②多查詢客戶端的支持

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

?

?

Ip2region V2.0 特性

①標準化的數據格式

每個 ip 數據段的 region 信息都固定了格式:國家|區域|省份|城市|ISP,只有中國的數據絕大部分精確到了城市,其他國家部分數據只能定位到國家,后前的選項全部是 0。

②數據去重和壓縮

xdb 格式生成程序會自動去重和壓縮部分數據,默認的全部 IP 數據,生成的 ip2region.xdb 數據庫是 11MiB,隨著數據的詳細度增加數據庫的大小也慢慢增大。

③極速查詢響應

即使是完全基于 xdb 文件的查詢,單次查詢響應時間在十微秒級別。

可通過如下兩種方式開啟內存加速查詢:

  • vIndex 索引緩存:使用固定的 512KiB 的內存空間緩存 vector index 數據,減少一次 IO 磁盤操作,保持平均查詢效率穩定在 10-20 微秒之間。

  • xdb 整個文件緩存:將整個 xdb 文件全部加載到內存,內存占用等同于 xdb 文件大小,無磁盤 IO 操作,保持微秒級別的查詢效率。

④極速查詢響應

v2.0 格式的 xdb 支持億級別的 IP 數據段行數,region 信息也可以完全自定義,例如:你可以在 region 中追加特定業務需求的數據,例如:GPS信息/國際統一地域信息編碼/郵編等。也就是你完全可以使用 ip2region 來管理你自己的 IP 定位數據。

ip2region xdb java 查詢客戶端實現

①使用方式

引入 maven 倉庫:

<dependency><groupId>org.lionsoul</groupId><artifactId>ip2region</artifactId><version>2.6.4</version> </dependency>

②完全基于文件的查詢

import org.lionsoul.ip2region.xdb.Searcher; import java.io.*; import java.util.concurrent.TimeUnit;public class SearcherTest {public static void main(String[] args) {// 1、創建 searcher 對象String dbPath = "ip2region.xdb file path";Searcher searcher = null;try {searcher = Searcher.newWithFileOnly(dbPath);} catch (IOException e) {System.out.printf("failed to create searcher with `%s`: %s\n", dbPath, e);return;}// 2、查詢try {String ip = "1.2.3.4";long sTime = System.nanoTime();String region = searcher.search(ip);long cost = TimeUnit.NANOSECONDS.toMicros((long) (System.nanoTime() - sTime));System.out.printf("{region: %s, ioCount: %d, took: %d μs}\n", region, searcher.getIOCount(), cost);} catch (Exception e) {System.out.printf("failed to search(%s): %s\n", ip, e);}// 3、備注:并發使用,每個線程需要創建一個獨立的 searcher 對象單獨使用。} }

③緩存 VectorIndex 索引

我們可以提前從 xdb 文件中加載出來 VectorIndex 數據,然后全局緩存,每次創建 Searcher 對象的時候使用全局的 VectorIndex 緩存可以減少一次固定的 IO 操作,從而加速查詢,減少 IO 壓力。

import org.lionsoul.ip2region.xdb.Searcher; import java.io.*; import java.util.concurrent.TimeUnit;public class SearcherTest {public static void main(String[] args) {String dbPath = "ip2region.xdb file path";// 1、從 dbPath 中預先加載 VectorIndex 緩存,并且把這個得到的數據作為全局變量,后續反復使用。byte[] vIndex;try {vIndex = Searcher.loadVectorIndexFromFile(dbPath);} catch (Exception e) {System.out.printf("failed to load vector index from `%s`: %s\n", dbPath, e);return;}// 2、使用全局的 vIndex 創建帶 VectorIndex 緩存的查詢對象。Searcher searcher;try {searcher = Searcher.newWithVectorIndex(dbPath, vIndex);} catch (Exception e) {System.out.printf("failed to create vectorIndex cached searcher with `%s`: %s\n", dbPath, e);return;}// 3、查詢try {String ip = "1.2.3.4";long sTime = System.nanoTime();String region = searcher.search(ip);long cost = TimeUnit.NANOSECONDS.toMicros((long) (System.nanoTime() - sTime));System.out.printf("{region: %s, ioCount: %d, took: %d μs}\n", region, searcher.getIOCount(), cost);} catch (Exception e) {System.out.printf("failed to search(%s): %s\n", ip, e);}// 備注:每個線程需要單獨創建一個獨立的 Searcher 對象,但是都共享全局的制度 vIndex 緩存。} }

④緩存整個 xdb 數據

我們也可以預先加載整個 ip2region.xdb 的數據到內存,然后基于這個數據創建查詢對象來實現完全基于文件的查詢,類似之前的 memory search。

import org.lionsoul.ip2region.xdb.Searcher; import java.io.*; import java.util.concurrent.TimeUnit;public class SearcherTest {public static void main(String[] args) {String dbPath = "ip2region.xdb file path";// 1、從 dbPath 加載整個 xdb 到內存。byte[] cBuff;try {cBuff = Searcher.loadContentFromFile(dbPath);} catch (Exception e) {System.out.printf("failed to load content from `%s`: %s\n", dbPath, e);return;}// 2、使用上述的 cBuff 創建一個完全基于內存的查詢對象。Searcher searcher;try {searcher = Searcher.newWithBuffer(cBuff);} catch (Exception e) {System.out.printf("failed to create content cached searcher: %s\n", e);return;}// 3、查詢try {String ip = "1.2.3.4";long sTime = System.nanoTime();String region = searcher.search(ip);long cost = TimeUnit.NANOSECONDS.toMicros((long) (System.nanoTime() - sTime));System.out.printf("{region: %s, ioCount: %d, took: %d μs}\n", region, searcher.getIOCount(), cost);} catch (Exception e) {System.out.printf("failed to search(%s): %s\n", ip, e);}// 備注:并發使用,用整個 xdb 數據緩存創建的查詢對象可以安全的用于并發,也就是你可以把這個 searcher 對象做成全局對象去跨線程訪問。} }

IDEA 中做個測試

?①完全基于文件的查詢

ip 屬地國內的話,會展示省份,國外的話,只會展示國家。可以通過如下圖這個方法進行進一步封裝,得到獲取 IP 屬地的信息。

?下面是官網給出的命令運行 jar 方式給出的測試 demo,可以理解下。

②編譯測試程序

通過 maven 來編譯測試程序。

#?cd?到?java?binding?的根目錄
cd?binding/java/
mvn?compile?package

然后會在當前目錄的 target 目錄下得到一個 ip2region-{version}.jar 的打包文件。

③查詢測試

可以通過 java -jar ip2region-{version}.jar search 命令來測試查詢:

???java?git:(v2.0_xdb)???java?-jar?target/ip2region-2.6.0.jar?search
java?-jar?ip2region-{version}.jar?search?[command?options]
options:
?--db?string??????????????ip2region?binary?xdb?file?path
?--cache-policy?string????cache?policy:?file/vectorIndex/content

例如:使用默認的 data/ip2region.xdb 文件進行查詢測試:

例如:使用默認的 data/ip2region.xdb 文件進行查詢測試:? java git:(v2.0_xdb) ? java -jar target/ip2region-2.6.0.jar search --db=../../data/ip2region.xdb ip2region xdb searcher test program, cachePolicy: vectorIndex type 'quit' to exit ip2region>> 1.2.3.4 {region: 美國|0|華盛頓|0|谷歌, ioCount: 7, took: 82 μs} ip2region>>

輸入 ip 即可進行查詢測試,也可以分別設置 cache-policy 為 file/vectorIndex/content 來測試三種不同緩存實現的查詢效果。

④bench 測試

可以通過 java -jar ip2region-{version}.jar bench 命令來進行 bench 測試,一方面確保 xdb 文件沒有錯誤,一方面可以評估查詢性能:

???java?git:(v2.0_xdb)???java?-jar?target/ip2region-2.6.0.jar?bench
java?-jar?ip2region-{version}.jar?bench?[command?options]
options:
?--db?string??????????????ip2region?binary?xdb?file?path
?--src?string?????????????source?ip?text?file?path
?--cache-policy?string????cache?policy:?file/vectorIndex/content

?

例如:通過默認的 data/ip2region.xdb 和 data/ip.merge.txt 文件進行 bench 測試:

? java git:(v2.0_xdb) ? java -jar target/ip2region-2.6.0.jar bench --db=../../data/ip2region.xdb --src=../../data/ip.merge.txt Bench finished, {cachePolicy: vectorIndex, total: 3417955, took: 8s, cost: 2 μs/op}

?

可以通過分別設置 cache-policy 為 file/vectorIndex/content 來測試三種不同緩存實現的效果。

@Note:注意 bench 使用的 src 文件要是生成對應 xdb 文件相同的源文件。

“到這里獲取用戶 IP 屬地已經完成啦,這篇文章介紹的 v2.0 版本,有興趣的小伙伴可以登錄上門的 github 地址了解下 v1.0 版本。

總結

以上是生活随笔為你收集整理的IP 属地功能实现的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。