在项目中经常会遇到获取IP地址归属地的需求。下面介绍一下如何纯真社区版IP库(qqwry.dat)获取ip归属地的工具类。
纯真IP库是一个用于检测中国互联网IP地址归属地的工具库,它提供了一种便捷的方式来识别用户的地理位置信息,通常用于网站、应用的防刷、地区定向等功能。这个库基于电信运营商的数据,将IP地址映射到具体的省份、城市甚至更详细的区县级别。使用纯真IP库可以帮助开发者快速验证用户IP,并基于位置信息做出相应的服务策略。
public class IPUtils {
private static final Logger log = LoggerFactory.getLogger(IPUtils.class);
private static final int IP_RECORD_LENGTH = 7;
private static final byte REDIRECT_MODE_1 = 0x01;
private static final byte REDIRECT_MODE_2 = 0x02;
private MappedByteBuffer mbbFile;
private static Long lastModifyTime = 0L;
private static ReentrantLock lock = new ReentrantLock();
private static ReentrantLock lockArgs = new ReentrantLock();
private File qqwryFile;
private long firstIndexOffset;
private long lastIndexOffset;
private long totalIndexCount;
private static String DATA_PATH = "qqwry.dat";
// 根据IP地址获取ip归属地
public String getCountry(String ip) {
lockArgs.lock();
String lo = "";
try {
if(null == qqwryFile || null == mbbFile){
init();
}
mbbFile.position(0);
firstIndexOffset = read4ByteAsLong(0);
lastIndexOffset = read4ByteAsLong(4);
totalIndexCount = (lastIndexOffset - firstIndexOffset) / IP_RECORD_LENGTH + 1;
lo = readIPLocation(search(inet_pton(ip))).getCountry();
}finally {
lockArgs.unlock();
}
return lo;
}
public void init(){
this.qqwryFile = new File(DATA_PATH);
try {
load();
} catch (Exception e) {
log.error("加载资源文件异常,"+e.getMessage());
}
}
public long read4ByteAsLong(long pos) {
mbbFile.position((int) pos);
return 0xFFFFFFFFL & mbbFile.getInt();
}
public long read3ByteAsLong(long pos) {
mbbFile.position((int) pos);
return 0xFFFFFFL & mbbFile.getInt();
}
private void load() throws Exception {
lastModifyTime = qqwryFile.lastModified();
lock.lock();
try {
mbbFile = new RandomAccessFile(qqwryFile, "r")
.getChannel()
.map(FileChannel.MapMode.READ_ONLY, 0, qqwryFile.length());
mbbFile.order(ByteOrder.LITTLE_ENDIAN);
} finally {
lock.unlock();
}
}
public long inet_pton(String ipStr) {
if (ipStr == null) {
throw new NullPointerException("ip不能为空");
}
String[] arr = ipStr.split("\\.");
long ip = (Long.parseLong(arr[0]) & 0xFFL) << 24 & 0xFF000000L;
ip |= (Long.parseLong(arr[1]) & 0xFFL) << 16 & 0xFF0000L;
ip |= (Long.parseLong(arr[2]) & 0xFFL) << 8 & 0xFF00L;
ip |= (Long.parseLong(arr[3]) & 0xFFL);
return ip;
}
public long search(long ip) {
long low = 0;
long high = totalIndexCount;
long mid = 0;
while (low <= high) {
mid = (low + high) >>> 1;
long indexIP = read4ByteAsLong(firstIndexOffset + (mid - 1) * IP_RECORD_LENGTH);
long nextIndexIP = read4ByteAsLong(firstIndexOffset + mid * IP_RECORD_LENGTH);
if (indexIP <= ip && ip < nextIndexIP) {
return read3ByteAsLong(firstIndexOffset + (mid - 1) * IP_RECORD_LENGTH + 4);
} else {
if (ip > indexIP) {
low = mid + 1;
} else if (ip < indexIP) {
high = mid - 1;
}
}
}
return -1;
}
public Location readIPLocation(long offset) {
try {
mbbFile.position((int) offset + 4);
Location loc = new Location();
byte redirectMode = mbbFile.get();
if (redirectMode == REDIRECT_MODE_1) {
long countryOffset = read3ByteAsLong((int) offset + 5);
mbbFile.position((int) countryOffset);
redirectMode = mbbFile.get();
if (redirectMode == REDIRECT_MODE_2) {
loc.setCountry(readString(read3ByteAsLong(countryOffset + 1)));
mbbFile.position((int) countryOffset + 4);
} else {
loc.setCountry( readString(countryOffset));
}
loc.setArea(readArea(mbbFile.position()));
} else if (redirectMode == REDIRECT_MODE_2) {
loc.setCountry (readString(read3ByteAsLong((int) offset + 5)));
loc.setArea (readArea((int) offset + 8));
} else {
loc.setCountry (readString(mbbFile.position() - 1));
loc.setArea (readArea(mbbFile.position()));
}
return loc;
} catch (Exception e) {
return null;
}
}
public String readArea(long offset) {
mbbFile.position((int) offset);
byte redirectMode = mbbFile.get();
if (redirectMode == REDIRECT_MODE_1 || redirectMode == REDIRECT_MODE_2) {
long areaOffset = read3ByteAsLong((int) offset + 1);
if (areaOffset == 0) {
return "";
} else {
return readString(areaOffset);
}
} else {
return readString(offset);
}
}
private String readString(long offset) {
try {
mbbFile.position((int) offset);
byte[] buf = new byte[128];
int i;
for (i = 0, buf[i] = mbbFile.get(); buf[i] != 0; buf[++i] = mbbFile.get()) ;
if (i != 0) {
return new String(buf, 0, i, "GBK");
}
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
}