
Java调用各大离线IP库方法
像我们这种开发网站的免不了跟IP打交道,我们经常需要搞清楚某个IP地址是谁在使用它。因此,我们需要一种能够将IP地址翻译成有意义的信息的方法。这就是IP库存在的意义,本文搜集了互联网上所有的离线IP库:zxipv6wry
,Ip2region
,Geoip
,Ip2location
,纯真IP库
当然有的里面信息可能已经过时或不准确。此处给出如何使用Java来调用这些IP库
库信息概览
库名 | 支持的IP类型 | 是否持续更新 | 备注 |
---|---|---|---|
ip2location | IPv4 / IPv6 | ✅ 是 | 商业数据库,但是提供Lite免费版本,仅提供Bin格式数据库。 |
GeoIP | IPv4 / IPv6 | ✅ 是 | MaxMind 提供,传统 GeoIP(旧版)已停止更新,GeoIP2(付费)每月更新,免费版(GeoLite2)每月更新。 |
ip2region | IPv4 | ✅ 是 | 开源项目(GitHub维护),支持IPv4,更新依赖社区贡献,近年活跃度较高。 |
纯真社区IP库 | IPv4 / IPv6 | ✅ 是 | 纯真数据库是国内首屈一指的数据库,其提供的离线IP库只要你通过授权就可以一直免费使用,每周三更新一次. |
zxipv6wry | IPv6 | ❌ 否 | 专为IPv6设计的离线库,已停止更新。 |
Ip2location
官网地址:
Maven地址
<dependency>
<groupId>net.renfei</groupId>
<artifactId>ip2location</artifactId>
<version>1.2.4</version>
</dependency>
其实这个库导的没有必要,这只是他方便我们使用写的我们完全可以直接把他代码扣下来用,并且自主实现AutoCloseable,这里仅仅演示我们就不这样干了直接使用官方提供的 Maven 依赖项即可。
创建IPInfo
类
package com.zftj.IP2Location;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* IP信息对象类,用于封装IP查询结果
* @author 17Yuns
*/
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class IPInfo {
// 查询的IP地址
private String ip;
// 国家代码(ISO 3166-1 Alpha-2)
@JsonProperty("country_code")
private String countryCode;
// 国家全名
@JsonProperty("country_name")
private String countryName;
// 省份/地区名称
private String region;
// 城市名称
private String city;
// 互联网服务提供商
private String isp;
// 纬度
private String latitude;
// 经度
private String longitude;
// IP所属域名
private String domain;
// 邮政编码
private String zipcode;
// 时区名称
private String timezone;
// 网络连接速度
private String netspeed;
// 自治系统编号(ASN)
private String asn;
// 用途类型(如 CDN、Dialup 等)
private String usagetype;
// 地址类型(如 Unicast、Multicast 等)
@JsonProperty("addresstype")
private String addressType;
// 类别(如 ISP、Hosting 等)
private String category;
// 行政区/区域名称
private String district;
// 海拔高度(单位:米)
private String elevation;
// 移动运营商品牌
private String mobilebrand;
// 国际电话区号
@JsonProperty("iddcode")
private String iddCode;
// 国内电话区号
@JsonProperty("areacode")
private String areaCode;
// 气象站代码
@JsonProperty("weatherstationcode")
private String weatherStationCode;
// 气象站名称
@JsonProperty("weatherstationname")
private String weatherStationName;
// 移动网络代码(MCC)
private String mcc;
// 移动网络代码(MNC)
private String mnc;
// 数据库版本信息
private String version;
}
创建IPError
类
package com.zftj.IP2Location;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
/**
* 错误信息对象类
* @author 17Yuns
*/
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class IPError {
// 错误状态码(如 INVALID_IP_ADDRESS)
private String status;
// 错误描述信息(如 "Invalid IP address.")
private String error;
// 出错的IP地址
private String ip;
public IPError(String status, String errorMessage, String ip) {
}
}
创建Main
类
package com.zftj.IP2Location;
import com.fasterxml.jackson.databind.ObjectMapper;
import net.renfei.ip2location.IP2Location;
import net.renfei.ip2location.IPResult;
import net.renfei.ip2location.IPTools;
import java.util.Map;
/**
* @author 17Yuns
* @version 1.0
*/
public class Main {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private static final Map<String, String> ERROR_MESSAGES = Map.of(
"EMPTY_IP_ADDRESS", "IP address cannot be blank.",
"INVALID_IP_ADDRESS", "Invalid IP address.",
"MISSING_FILE", "Invalid database path.",
"IPV6_NOT_SUPPORTED", "This BIN does not contain IPv6 data."
);
private static final String DB11_V4 = "src/main/resources/ipdata/ip2location/IP2LOCATION-LITE-DB11.bin";
private static final String DB11_V6 = "src/main/resources/ipdata/ip2location/IP2LOCATION-LITE-DB11.IPV6.bin";
public static void main(String[] args) {
IP2Location loc = new IP2Location();
String binfile = null;
try {
String ip = "23.214.45.23";
boolean isIPv4 = new IPTools().IsIPv4(ip);
binfile = isIPv4 ? DB11_V4 : DB11_V6;
loc.Open(binfile, true);
IPResult rec = loc.IPQuery(ip);
if ("OK".equals(rec.getStatus())) {
IPInfo info = getIpInfo(ip, rec);
System.out.println(toJson(info));
} else {
IPError error = getIpError(rec, ip);
System.out.println(toJson(error));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
loc.Close();
}
}
private static IPInfo getIpInfo(String ip, IPResult rec) {
IPInfo info = new IPInfo();
info.setIp(ip);
info.setCountryCode(rec.getCountryShort());
info.setCountryName(rec.getCountryLong());
info.setRegion(rec.getRegion());
info.setCity(rec.getCity());
info.setIsp(rec.getISP());
info.setLatitude(String.valueOf(rec.getLatitude()));
info.setLongitude(String.valueOf(rec.getLongitude()));
info.setDomain(rec.getDomain());
info.setZipcode(rec.getZipCode());
info.setTimezone(rec.getTimeZone());
info.setNetspeed(rec.getNetSpeed());
info.setAsn(rec.getASN());
info.setUsagetype(rec.getUsageType());
info.setAddressType(rec.getAddressType());
info.setCategory(rec.getCategory());
info.setDistrict(rec.getDistrict());
info.setElevation(String.valueOf(rec.getElevation()));
info.setMobilebrand(rec.getMobileBrand());
info.setIddCode(rec.getIDDCode());
info.setAreaCode(rec.getAreaCode());
info.setWeatherStationCode(rec.getWeatherStationCode());
info.setWeatherStationName(rec.getWeatherStationName());
info.setMcc(rec.getMCC());
info.setMnc(rec.getMNC());
info.setVersion(rec.getVersion());
return info;
}
private static IPError getIpError(IPResult rec, String ip) {
String errorMessage = ERROR_MESSAGES.getOrDefault(rec.getStatus(), "Unknown error: " + rec.getStatus());
return new IPError(rec.getStatus(), errorMessage, ip);
}
private static String toJson(Object obj) {
try {
return OBJECT_MAPPER.writeValueAsString(obj);
} catch (Exception e) {
throw new RuntimeException("JSON序列化失败", e);
}
}
}
运行结果
{
"ip": "23.214.45.23",
"region": "New South Wales",
"city": "Sydney",
"isp": "Not_Supported",
"latitude": "-33.86778",
"longitude": "151.20705",
"domain": "Not_Supported",
"zipcode": "2000",
"timezone": "+10:00",
"netspeed": "Not_Supported",
"asn": "Not_Supported",
"usagetype": "Not_Supported",
"category": "Not_Supported",
"district": "Not_Supported",
"elevation": "0.0",
"mobilebrand": "Not_Supported",
"mcc": "Not_Supported",
"mnc": "Not_Supported",
"version": "Version 8.11.2",
"country_code": "AU",
"country_name": "Australia",
"addresstype": "Not_Supported",
"iddcode": "Not_Supported",
"areacode": "Not_Supported",
"weatherstationcode": "Not_Supported",
"weatherstationname": "Not_Supported"
}
Ip2region
这也是非常优秀的IP库,官方实例写的非常清楚,此处仅做总结
Maven仓库
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
<version>2.7.0</version>
</dependency>
创建Main类
package com.zftj.ip2region;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.lionsoul.ip2region.xdb.Searcher;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.HashMap;
import java.util.Map;
/**
* @author 17Yuns
* @version 1.0
*/
public class Main {
public static void main(String[] args) throws IOException {
// 使用 ClassLoader 加载 resources 下的 ip2region.xdb 文件
String dbPath;
try (InputStream inputStream = Main.class.getClassLoader().getResourceAsStream("ipdata/ip2region/ip2region.xdb")) {
if (inputStream == null) {
System.out.println("Failed to load ip2region.xdb from resources.");
return;
}
// 将资源文件复制到临时文件
Path tempFile = Files.createTempFile("ip2region", ".xdb");
Files.copy(inputStream, tempFile, StandardCopyOption.REPLACE_EXISTING);
dbPath = tempFile.toAbsolutePath().toString();
} catch (Exception e) {
System.out.printf("Failed to load ip2region.xdb: %s\n", e);
return;
}
// 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、查询
String ip = null;
try {
ip = "23.214.45.23";
String region = searcher.search(ip);
// System.out.printf("{region: %s, ioCount: %d, took: %d μs}\n", region, searcher.getIOCount(), cost);
// 解析结果并输出JSON
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("ip", ip);
resultMap.put("region", region);
resultMap.putAll(parseIp2RegionResult(region));
// 转换为JSON输出
ObjectMapper objectMapper = new ObjectMapper();
String jsonResult = objectMapper.writeValueAsString(resultMap);
System.out.println(jsonResult);
} catch (Exception e) {
System.out.printf("failed to search(%s): %s\n", ip, e);
}
// 4、关闭资源
searcher.close();
}
/**
* 解析 ip2region 返回的结果字符串
* 格式通常为: "国家|区域|城市|运营商|ISP"
*/
private static Map<String, String> parseIp2RegionResult(String region) {
Map<String, String> result = new HashMap<>();
if (region == null || region.isEmpty()) {
return result;
}
String[] parts = region.split("\\|");
if (parts.length >= 1) {
String country = parts[0].trim();
if (!"0".equals(country)) {
result.put("country", country);
}
}
if (parts.length >= 2) {
String area = parts[1].trim();
if (!"0".equals(area)) {
result.put("area", area);
}
}
if (parts.length >= 3) {
String city = parts[2].trim();
if (!"0".equals(city)) {
result.put("city", city);
}
}
if (parts.length >= 4) {
String provider = parts[3].trim();
if (!"0".equals(provider)) {
result.put("provider", provider);
}
}
if (parts.length >= 5) {
String isp = parts[4].trim();
if (!"0".equals(isp)) {
result.put("isp", isp);
}
}
return result;
}
}
运行结果
{"country":"美国","city":"德克萨斯","provider":"达拉斯","ip":"23.214.45.23","isp":"阿卡迈","region":"美国|0|德克萨斯|达拉斯|阿卡迈"}
GEOIP库
本文章采用的是大佬修改后的版本以及官方版,统一进行查询在不同字段下进行展示,这个库信息提供的挺多的
Maven库
<dependency>
<groupId>com.maxmind.geoip2</groupId>
<artifactId>geoip2</artifactId>
<version>4.2.1</version>
</dependency>
<dependency>
<groupId>com.maxmind.db</groupId>
<artifactId>maxmind-db</artifactId>
<version>2.0.0</version>
</dependency>
创建GeoIpService类
package com.zftj.geoip;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.maxmind.geoip2.DatabaseReader;
import com.maxmind.geoip2.exception.AddressNotFoundException;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
/**
* 使用MaxMind数据库进行IP地理位置查询的服务
*
* @author 17Yuns
* @version 1.1
*/
public class GeoIpService implements Closeable {
private static final String RESOURCE_PATH = "ipdata/geoip/";
private final ObjectMapper objectMapper;
private final DatabaseReader countryReader;
private final DatabaseReader asnReader;
private final DatabaseReader countryWithoutAsnReader;
private final DatabaseReader countryAsnReader;
/**
* 创建新的GeoIpService实例并初始化数据库读取器
*
* @throws IOException 如果数据库文件无法加载
*/
public GeoIpService() throws IOException {
this.objectMapper = new ObjectMapper();
// 初始化数据库读取器
this.countryReader = createReader(RESOURCE_PATH + "GeoLite2-Country.mmdb");
this.asnReader = createReader(RESOURCE_PATH + "GeoLite2-ASN.mmdb");
this.countryWithoutAsnReader = createReader(RESOURCE_PATH + "Country-without-asn.mmdb");
this.countryAsnReader = createReader(RESOURCE_PATH + "Country-asn.mmdb");
}
/**
* 从资源文件创建DatabaseReader的辅助方法
*/
private DatabaseReader createReader(String resourcePath) throws IOException {
InputStream is = getClass().getClassLoader().getResourceAsStream(resourcePath);
if (is == null) {
throw new IOException("未找到资源: " + resourcePath);
}
return new DatabaseReader.Builder(is).build();
}
/**
* 查询IP地址的地理位置数据并以JSON字符串形式返回
*
* @param ipAddress 要查询的IP地址
* @return 包含地理位置数据的JSON字符串
* @throws Exception 如果查询失败
*/
public String lookupIp(String ipAddress) throws Exception {
InetAddress ipAddr = InetAddress.getByName(ipAddress);
// 创建根JSON结构
ObjectNode rootNode = objectMapper.createObjectNode();
ObjectNode geoipNode = objectMapper.createObjectNode();
ObjectNode normalNode = objectMapper.createObjectNode();
ObjectNode plusNode = objectMapper.createObjectNode();
// 填充普通数据
addLookupResult(normalNode, "country", () -> countryReader.country(ipAddr));
addLookupResult(normalNode, "asn", () -> asnReader.asn(ipAddr));
// 填充plus数据
addLookupResult(plusNode, "country", () -> countryWithoutAsnReader.country(ipAddr));
addLookupResult(plusNode, "asn", () -> countryAsnReader.country(ipAddr));
// 仅将非空节点添加到结果中
if (!normalNode.isEmpty()) {
geoipNode.set("normal", normalNode);
}
if (!plusNode.isEmpty()) {
geoipNode.set("plus", plusNode);
}
rootNode.set("geoip", geoipNode);
return objectMapper.writeValueAsString(rootNode);
}
/**
* 将查询结果添加到JSON节点的辅助方法,处理异常
*/
private <T> void addLookupResult(ObjectNode parentNode, String key, LookupOperation<T> operation) {
try {
T result = operation.lookup();
if (result != null) {
JsonNode jsonNode = objectMapper.valueToTree(result);
parentNode.set(key, jsonNode);
}
} catch (AddressNotFoundException e) {
// IP在数据库中未找到,跳过此结果
} catch (Exception e) {
// 记录错误但继续处理其他查询
e.printStackTrace();
}
}
/**
* IP查询的函数式接口
*/
@FunctionalInterface
private interface LookupOperation<T> {
T lookup() throws Exception;
}
@Override
public void close() {
try {
countryReader.close();
asnReader.close();
countryWithoutAsnReader.close();
countryAsnReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
创建Main类
package com.zftj.geoip;
/**
* @author 17Yuns
* @version 1.0
*/
public class Main {
public static void main(String[] args) {
try (GeoIpService service = new GeoIpService()) {
String ipAddress = "23.214.45.23";
String result = service.lookupIp(ipAddress);
System.out.println(result);
} catch (Exception e) {
System.err.println("处理IP查询时出错: " + e.getMessage());
e.printStackTrace();
}
}
}
运行结果
{
"geoip": {
"normal": {
"country": {
"continent": {
"code": "OC",
"geoname_id": 6255151,
"names": {
"de": "Ozeanien",
"ru": "Океания",
"pt-BR": "Oceania",
"ja": "オセアニア",
"en": "Oceania",
"fr": "Océanie",
"zh-CN": "大洋洲",
"es": "Oceanía"
}
},
"country": {
"confidence": null,
"geoname_id": 2077456,
"is_in_european_union": false,
"iso_code": "AU",
"names": {
"de": "Australien",
"ru": "Австралия",
"pt-BR": "Austrália",
"ja": "オーストラリア",
"en": "Australia",
"fr": "Australie",
"zh-CN": "澳大利亚",
"es": "Australia"
}
},
"maxmind": {
"queries_remaining": null
},
"registered_country": {
"confidence": null,
"geoname_id": 6252001,
"is_in_european_union": false,
"iso_code": "US",
"names": {
"de": "USA",
"ru": "США",
"pt-BR": "EUA",
"ja": "アメリカ",
"en": "United States",
"fr": "États Unis",
"zh-CN": "美国",
"es": "Estados Unidos"
}
},
"represented_country": {
"confidence": null,
"geoname_id": null,
"is_in_european_union": false,
"iso_code": null,
"names": {},
"type": null
},
"traits": {
"autonomous_system_number": null,
"autonomous_system_organization": null,
"connection_type": null,
"domain": null,
"ip_address": "23.214.45.23",
"is_anonymous": false,
"is_anonymous_proxy": false,
"is_anonymous_vpn": false,
"is_anycast": false,
"is_hosting_provider": false,
"is_legitimate_proxy": false,
"is_public_proxy": false,
"is_residential_proxy": false,
"is_satellite_provider": false,
"is_tor_exit_node": false,
"isp": null,
"mobile_country_code": null,
"mobile_network_code": null,
"network": "23.214.32.0/19",
"organization": null,
"user_type": null,
"user_count": null,
"static_ip_score": null
}
},
"asn": {
"autonomous_system_number": 16625,
"autonomous_system_organization": "AKAMAI-AS",
"ip_address": "23.214.45.23",
"network": "23.214.32.0/19"
}
},
"plus": {
"country": {
"continent": {
"code": null,
"geoname_id": null,
"names": {}
},
"country": {
"confidence": null,
"geoname_id": 2077456,
"is_in_european_union": false,
"iso_code": "AU",
"names": {
"de": "Australien",
"ru": "Австралия",
"pt-BR": "Austrália",
"ja": "オーストラリア",
"en": "Australia",
"fr": "Australie",
"zh-CN": "澳大利亚",
"es": "Australia"
}
},
"maxmind": {
"queries_remaining": null
},
"registered_country": {
"confidence": null,
"geoname_id": null,
"is_in_european_union": false,
"iso_code": null,
"names": {}
},
"represented_country": {
"confidence": null,
"geoname_id": null,
"is_in_european_union": false,
"iso_code": null,
"names": {},
"type": null
},
"traits": {
"autonomous_system_number": null,
"autonomous_system_organization": null,
"connection_type": null,
"domain": null,
"ip_address": "23.214.45.23",
"is_anonymous": false,
"is_anonymous_proxy": false,
"is_anonymous_vpn": false,
"is_anycast": false,
"is_hosting_provider": false,
"is_legitimate_proxy": false,
"is_public_proxy": false,
"is_residential_proxy": false,
"is_satellite_provider": false,
"is_tor_exit_node": false,
"isp": null,
"mobile_country_code": null,
"mobile_network_code": null,
"network": "23.214.32.0/19",
"organization": null,
"user_type": null,
"user_count": null,
"static_ip_score": null
}
}
}
}
}
CZ88(纯真数据库)
官方实例写的也很清晰,此处简要提及
Maven库
<dependency>
<groupId>net.cz88</groupId>
<artifactId>czdb-search</artifactId>
<version>1.0.2.7</version>
</dependency>
创建Main类
package com.zftj.czdb;
import com.fasterxml.jackson.databind.ObjectMapper;
import net.cz88.czdb.DbSearcher;
import net.cz88.czdb.QueryType;
import net.renfei.ip2location.IPTools;
import java.util.HashMap;
import java.util.Map;
/**
* @author 17Yuns
* @version 1.0
*/
public class Main {
public static void main(String[] args) throws Exception {
String ip = "23.224.56.23";
String key = "";//这个key你得自己去申请
boolean isIPv4 = new IPTools().IsIPv4(ip);
String dbPath=null;
if (isIPv4){
dbPath="src/main/resources/ipdata/czdb/cz88_public_v4.czdb";
}else {
dbPath="src/main/resources/ipdata/czdb/cz88_public_v6.czdb";
}
DbSearcher searcher = new DbSearcher(dbPath, QueryType.MEMORY, key);
try {
String region = searcher.search(ip);
// 创建结果Map
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("ip", ip);
resultMap.put("region", region);
// 灵活处理不同格式的返回结果
Map<String, String> parsedFields = parseRegion(region);
resultMap.putAll(parsedFields);
// 转换为JSON字符串
ObjectMapper objectMapper = new ObjectMapper();
String jsonResult = objectMapper.writeValueAsString(resultMap);
// 输出JSON字符串
System.out.println(jsonResult);
} finally {
searcher.close();
}
}
private static Map<String, String> parseRegion(String region) {
Map<String, String> result = new HashMap<>();
if (region.contains("–")) {
// 处理标准格式 "国家–省份–城市–区域 ISP"
String[] parts = region.split("–");
if (parts.length >= 1) {
result.put("country", parts[0].trim());
}
if (parts.length >= 2) {
result.put("province", parts[1].trim());
}
if (parts.length >= 3) {
result.put("city", parts[2].trim());
}
if (parts.length >= 4) {
String areaIsp = parts[3].trim();
// 首先检查是否含有制表符
int tabIndex = areaIsp.indexOf("\t");
if (tabIndex > 0) {
result.put("area", areaIsp.substring(0, tabIndex).trim());
result.put("isp", areaIsp.substring(tabIndex + 1).trim());
} else {
// 再检查是否含有空格
int spaceIndex = areaIsp.indexOf(" ");
if (spaceIndex > 0) {
result.put("area", areaIsp.substring(0, spaceIndex).trim());
result.put("isp", areaIsp.substring(spaceIndex + 1).trim());
} else {
result.put("area", areaIsp);
}
}
}
} else if (region.contains("\t")) {
// 处理类似 "澳大利亚\tAPNIC_Debogon-prefix网络" 的格式
String[] parts = region.split("\t");
if (parts.length >= 1) {
result.put("country", parts[0].trim());
}
if (parts.length >= 2) {
result.put("network", parts[1].trim());
}
} else if (region.contains(" ")) {
// 处理简单的空格分隔形式
int spaceIndex = region.indexOf(" ");
result.put("country", region.substring(0, spaceIndex).trim());
result.put("info", region.substring(spaceIndex + 1).trim());
} else {
// 无法分割的情况
result.put("info", region.trim());
}
return result;
}
}
运行结果
{
"area": "洛杉矶",
"country": "美国",
"province": "加利福尼亚州",
"city": "洛杉矶",
"ip": "23.224.56.23",
"isp": "Coperation_Coloction数据中心",
"region": "美国–加利福尼亚州–洛杉矶–洛杉矶\tCoperation_Coloction数据中心"
}
ZXIPV6WRY
这个库仅支持IPv6并且已经停止更新了,搞这个其实意义不大
下载地址:
https://ip.zxinc.org/ip.7z
里面有很详细的各语言调用方法。
IP库下载地址
本博客书写之时已经下载过一遍,因为文件过大,便不在浪费服务器资源采用百度网盘的方式,口令为本站域名。当然纯真数据库我已经删除,请去自行获取授权
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 17Yuns
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果