純真資料庫理解及根據IP定位地區
在系統中,檢視使用者的登入資訊是一個很常見的功能。我們往往會記錄下使用者計算機的IP和地理位置,然而IP地址記錄非常容易,但是地理位置相對來說較難。開始,菜鳥是想建立一個IP地址庫,根據IP地址庫查詢相應的地理位置。後來想有沒有一個相對完整的IP地址庫供菜鳥使用了,於是找到了一個QQwry.dat(純真資料庫)。然而,QQwry.dat是什麼呢?以及怎麼使用?
一、純真資料庫(QQwry.dat)
1.基本結構
QQwry.dat檔案在結構上分為檔案頭、記錄區和索引區3部分。我們一般在使用時先從索引區查詢記錄偏移,根據記錄偏移在從記錄區中獲取。由於記錄區是不定長的,且比較多,因此,一般採用二分查詢法進行查詢。
2.檔案頭
QQwry.dat檔案的標頭檔案結構非常簡單,為8個位元組。前4個位元組為第一條索引的絕對偏移,後4個位元組為最後一條索引的絕對偏移。
3.記錄區
每條IP地址的記錄區都由國家和地區組成,但是在這裡國家和地區都不太明確,相對而言的。國家可能是指一所學校,地區可能指學校中的某一系。於是我們想著IP地址的記錄格式可能為:[IP地址][國家名稱][地區名稱]。
國家和地區可能有很多重複,因此我們我可以用重定向來節約空間。其重定向有兩種方式:一種是直接用字串表示國家或地區;另一種是一個4位元組的結構,第1個位元組表示重定向的模式,後3個位元組表示國家名稱或地區名稱的實際偏移位置。
重定向的模式分為兩種:一種是隻有國家,沒有地區,也就是說地區記錄跟著國家記錄走了,在IP地址之後只剩下國家記錄的4個位元組,後3個位元組是一個指標,指向了實際的國家名稱,其標識位元組為0X01。另一種是既有國家又有地址,即地區記錄沒有跟著國家記錄走。在4個位元組的國家記錄後還含有地區記錄,其標識位元組為0X02。
4.索引區
通過了解“檔案頭”,我們可以瞭解到檔案頭實際上是兩個指標,分別指向檔案的第一條索引和最後一條索引的絕對偏移。我們可以根據標頭檔案定位到索引區,然後開始查詢IP。每條索引區為7個位元組,前4個位元組表示起始IP地址,後3個位元組表示結束IP地址。如222.11.0.1-222.11.0.240,222.11.0.1表示起始IP地址,222.11.0.240表示結束IP地址。若我們要查詢的IP地址在這個IP地址的範圍內,則根據這條索引區查詢國家和地區。二、例項
1.IP地址實體,包含起始、結束IP、國家名稱和地區名稱
package com.test.ip.entity; public class IpEntity { private String startIp;// 起始IP private String endIp;// 結尾IP private String country;// 國家 private String area;// 區域 // 構造方法:清空資料資訊 public IpEntity() { super(); this.startIp = ""; this.endIp = ""; this.country = ""; this.area = ""; } // getter和setter方法提供屬性對外訪問介面 public String getStartIp() { return startIp; } public void setStartIp(String startIp) { this.startIp = startIp; } public String getEndIp() { return endIp; } public void setEndIp(String endIp) { this.endIp = endIp; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public String getArea() { return area; } public void setArea(String area) { this.area = area; } }
2.位置實體
package com.test.ip.entity; /** * 封裝IP資訊,如國家和地區 * * @author aleyn * */ public class IpLocation { private String country;// 國家 private String area;// 地區 // 構造方法 public IpLocation() { this.country = ""; this.area = ""; } public IpLocation getCopy() { IpLocation ipLocation = new IpLocation(); ipLocation.setCountry(this.getCountry()); ipLocation.setArea(this.getArea()); return ipLocation; } // getter、setter public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public String getArea() { return area; } public void setArea(String area) { // 若為區域網,純真IP地址庫的地區會顯示CZ88.NET,去除 if (area.trim().equals("CZ88.NET")) { this.area = "區域網"; } else { this.area = area; } } }
3.轉換工具類
package com.test.ip.util;
import java.util.StringTokenizer;
/**
* 轉換工具
*
* @author aleyn
*
*/
public class ConvertUtils {
private static StringBuffer sb = new StringBuffer();
/**
* IP字串轉位元組陣列
*
* @param ip
* @return
*/
public static byte[] getIpArray(String ip) {
byte[] buffer = new byte[4];
StringTokenizer stringTokenizer = new StringTokenizer(ip, ".");
try {
buffer[0] = (byte) (Integer.parseInt(stringTokenizer.nextToken()) & 0xFF);
buffer[1] = (byte) (Integer.parseInt(stringTokenizer.nextToken()) & 0xFF);
buffer[2] = (byte) (Integer.parseInt(stringTokenizer.nextToken()) & 0xFF);
buffer[3] = (byte) (Integer.parseInt(stringTokenizer.nextToken()) & 0xFF);
} catch (Exception e) {
e.printStackTrace();
}
return buffer;
}
/**
* IP位元組陣列換字串
*
* @param ip
* @return
*/
public static String getIpString(byte[] ip) {
sb.delete(0, sb.length());
sb.append(ip[0] & 0xFF);
sb.append(".");
sb.append(ip[1] & 0xFF);
sb.append(".");
sb.append(ip[2] & 0xFF);
sb.append(".");
sb.append(ip[3] & 0xFF);
return sb.toString();
}
/**
* 根據某種編碼將IP位元組陣列轉為字串
*
* @param ip
* @param offset
* @param length
* @param encode
* @return
*/
public static String getIpString(byte[] ip, int offset, int length,
String encode) {
try {
return new String(ip, offset, length, encode);
} catch (Exception e) {
return new String(ip, offset, length);
}
}
}
4.讀取國家或地區工具類
package com.test.ip.util;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
public class ReadUtils {
/**
* 從offset未知讀取一個4位元組為一個long java格式為big-endian
*
* @param offset
* @return
*/
public static long readLongByFour(RandomAccessFile randomAccessFile,
long offset) {
long result = 0;
try {
randomAccessFile.seek(offset);
result |= (randomAccessFile.readByte() & 0xFF);
result |= ((randomAccessFile.readByte() << 8) & 0xFF00);
result |= ((randomAccessFile.readByte() << 16) & 0xFF0000);
result |= ((randomAccessFile.readByte() << 24) & 0xFF000000);
return result;
} catch (Exception e) {
return -1;
}
}
/**
* 從offset位置開始讀取3個位元組為一個long
*
* @param randomAccessFile
* @param offset
* @param buffer
* @return
*/
public static long readLongByThree(RandomAccessFile randomAccessFile,
long offset, byte[] buffer) {
long result = 0;
try {
randomAccessFile.seek(offset);
randomAccessFile.readFully(buffer);
result |= (buffer[0] & 0xFF);
result |= ((buffer[1] << 8) & 0xFF00);
result |= ((buffer[2] << 16) & 0xFF0000);
return result;
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
/**
* 從當前位置讀取3個位元組為一個long
*
* @param randomAccessFile
* @param buffer
* @return
*/
public static long readLongByThree(RandomAccessFile randomAccessFile,
byte[] buffer) {
long result = 0;
try {
randomAccessFile.readFully(buffer);
result |= (buffer[0] & 0xFF);
result |= ((buffer[1] << 8) & 0xFF00);
result |= ((buffer[2] << 16) & 0xFF0000);
return result;
} catch (Exception e) {
return -1;
}
}
/**
* 從記憶體對映的offset位置,開始3個位元組讀取一個int
*
* @param offset
* @return
*/
public static int readIntByThree(MappedByteBuffer mappedByteBuffer,
int offset) {
mappedByteBuffer.position(offset);
return mappedByteBuffer.getInt() & 0x00FFFFFF;
}
/**
* 從記憶體對映的當前位置,開始3個位元組讀取一個int
*
* @param mappedByteBuffer
* @return
*/
public static int readIntByThree(MappedByteBuffer mappedByteBuffer) {
return mappedByteBuffer.getInt() & 0x00FFFFFF;
}
/**
* 從offset位置讀取4個位元組的IP地址放入IP陣列中,讀取後的IP地址格式為big-endian
*
* @param offset
* @param ip
*/
public static void readIp(RandomAccessFile randomAccessFile, long offset,
byte[] ip) {
try {
randomAccessFile.seek(offset);
randomAccessFile.readFully(ip);
byte temp = ip[0];
ip[0] = ip[3];
ip[3] = temp;
temp = ip[1];
ip[1] = ip[2];
ip[2] = temp;
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 從offset位置讀取一個以0結束的字串
*
* @param offset
* @return
*/
public static String readString(RandomAccessFile randomAccessFile,
long offset, byte[] buffer) {
try {
randomAccessFile.seek(offset);
int i;
for (i = 0, buffer[i] = randomAccessFile.readByte(); buffer[i] != 0; buffer[++i] = randomAccessFile
.readByte())
;
if (i != 0) {
return ConvertUtils.getIpString(buffer, 0, i, "GBK");
}
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
/**
* 從offset位置讀取一個以0結束的字串
*
* @param offset
* @return
*/
public static String readString(MappedByteBuffer mappedByteBuffer,
int offset, byte[] buffer) {
try {
mappedByteBuffer.position(offset);
int i;
for (i = 0, buffer[i] = mappedByteBuffer.get(); buffer[i] != 0; buffer[++i] = mappedByteBuffer
.get())
;
if (i != 0)
return ConvertUtils.getIpString(buffer, 0, i, "GBK");
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
return "";
}
/**
* 從offset位置讀取4個位元組的IP地址放入IP陣列中,讀取後的IP地址格式為big-endian
*
* @param mappedByteBuffer
* @param offset
* @param ip
*/
public static void readIp(MappedByteBuffer mappedByteBuffer, int offset,
byte[] ip) {
try {
mappedByteBuffer.position(offset);
mappedByteBuffer.get(ip);
byte temp = ip[0];
ip[0] = ip[3];
ip[3] = temp;
temp = ip[1];
ip[1] = ip[2];
ip[2] = temp;
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 比較兩個位元組的大小
*
* @param b1
* @param b2
* @return
*/
private static int compareByte(byte b1, byte b2) {
if ((b1 & 0xFF) > (b2 & 0xFF)) // 比較是否大於
return 1;
else if ((b1 ^ b2) == 0)// 判斷是否相等
return 0;
else
return -1;
}
/**
* 將要查詢的IP和起始的IP進行比較
*
* @param ip
* @param beginIp
* @return
*/
public static int compareIp(byte[] ip, byte[] beginIp) {
for (int i = 0; i < 4; i++) {
int j = compareByte(ip[i], beginIp[i]);
if (j != 0) {
return j;
}
}
return 0;
}
}
5.提示訊息
package com.test.ip.util;/**
* 提示資訊
*
* @author aleyn
*
*/
public interface Message {
public static final String BAD_IP_FILE = "IP地址庫檔案錯誤";
public static final String UNKNOW_COUNTRY = "未知國家";
public static final String UNKNOW_AREA = "未知區域";
}
6.IP檢視器
package com.test.ip.viewer;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteOrder;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.test.ip.entity.IpEntity;
import com.test.ip.entity.IpLocation;
import com.test.ip.util.ConvertUtils;
import com.test.ip.util.LogFactory;
import com.test.ip.util.Message;
import com.test.ip.util.ReadUtils;
public class IpViewer {
private String fileName = "qqwry.dat";// 純真IP資料庫名
private String fileDir = null;// 儲存的資料夾
// 固定常量,如記錄長度
private static final int IP_RECORD_LENGTH = 7;
private static final byte REDIRECT_MODE_ONE = 0x01;
private static final byte REDIRECT_MODE_TWO = 0x02;
// 快取已經查詢過的IP地址,避免二次查詢,加快速度
private Map<String, IpLocation> cache;
// 隨機檔案訪問類
private RandomAccessFile randomAccessFile;
// 記憶體對映檔案
private MappedByteBuffer mappedByteBuffer;
// 起始地區的開始和結束絕對偏移量
private long begin, end;
// 為提高效率,臨時變數
private IpLocation ipLocation;
private byte[] buffer;
private byte[] bufferOne;
private byte[] bufferTwo;
/**
* 初始化
*/
public IpViewer() {
// 獲取檔案路徑和名稱
String path = IpViewer.class.getResource("").getPath() + fileName;
fileName = path;
// 初始化變數
this.cache = new HashMap<String, IpLocation>();
this.ipLocation = new IpLocation();
this.buffer = new byte[100];
this.bufferOne = new byte[3];
this.bufferTwo = new byte[4];
try {
randomAccessFile = new RandomAccessFile(fileName, "r");
} catch (FileNotFoundException e) {
// 若檔案找不到,在當前目錄下重新搜尋,並將檔名全部改為小寫(有些系統只能識別小寫)
String name = new File(fileName).getName().toLowerCase();
File[] files = new File(fileDir).listFiles();
for (int i = 0; i < files.length; i++) {
// 判斷是否是檔案
if (files[i].isFile()) {
// 判斷檔名稱
if (files[i].getName().toLowerCase().equals(name)) {
try {
randomAccessFile = new RandomAccessFile(files[i],
"r");
} catch (FileNotFoundException fileNotFoundException) {
e.printStackTrace();
fileName = null;
}
break;
}
}
}
}
// 若檔案開啟成功,讀取檔案頭資訊
if (randomAccessFile != null) {
try {
begin = ReadUtils.readLongByFour(randomAccessFile, 0);
end = ReadUtils.readLongByFour(randomAccessFile, 4);
if (begin == -1 || end == -1) {
randomAccessFile.close();
randomAccessFile = null;
}
} catch (Exception e) {
e.printStackTrace();
randomAccessFile = null;
}
}
}
/**
* 給定一個不完全的地點名稱,得到包含該地點的IP範圍記錄
*
* @param str
* @return
*/
public List<IpEntity> getIpEntityDebug(String str) {
List<IpEntity> list = new ArrayList<IpEntity>();
long endOffset = end + 4;
for (long offset = begin + 4; offset < endOffset; offset += IP_RECORD_LENGTH) {
// 讀取結束IP偏移量
long temp = ReadUtils.readLongByThree(randomAccessFile, offset,
bufferOne);
// 若temp不等於-1,則讀取IP資訊
if (temp != -1) {
IpLocation ipLocation = this.getIpLocation(temp);
// 判斷是否包含改地名,若包含,擇新增到list
if (ipLocation.getCountry().indexOf(str) != -1
|| ipLocation.getArea().indexOf(str) != -1) {
IpEntity ipEntity = new IpEntity();
ipEntity.setCountry(ipLocation.getCountry());
ipEntity.setArea(ipLocation.getArea());
// 獲取起始IP
ReadUtils.readIp(randomAccessFile, offset - 4, bufferTwo);
ipEntity.setStartIp(ConvertUtils.getIpString(bufferTwo));
// 獲取結束IP
ReadUtils.readIp(randomAccessFile, temp, bufferTwo);
ipEntity.setEndIp(ConvertUtils.getIpString(bufferTwo));
list.add(ipEntity);
}
}
}
return list;
}
public List<IpEntity> getIpEntity(String s) {
List<IpEntity> list = new ArrayList<IpEntity>();
try {
// 對映IP資訊檔案到記憶體中
if (mappedByteBuffer == null) {
FileChannel fc = randomAccessFile.getChannel();
mappedByteBuffer = fc.map(FileChannel.MapMode.READ_ONLY, 0,
randomAccessFile.length());
mappedByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
}
int endOffset = (int) end;
for (int offset = (int) begin + 4; offset <= endOffset; offset += IP_RECORD_LENGTH) {
int temp = ReadUtils.readIntByThree(mappedByteBuffer, offset);
if (temp != -1) {
IpLocation location = this.getIpLocation(temp);
// 地點是否包含要查詢的地點名稱
if (location.getCountry().indexOf(s) != -1
|| location.getArea().indexOf(s) != -1) {
IpEntity entity = new IpEntity();
entity.setCountry(location.getCountry());
entity.setArea(location.getArea());
// 得到起始IP
ReadUtils.readIp(mappedByteBuffer, offset, bufferTwo);
entity.setStartIp(ConvertUtils.getIpString(bufferTwo));
// 得到結束IP
ReadUtils.readIp(mappedByteBuffer, temp, bufferTwo);
entity.setEndIp(ConvertUtils.getIpString(bufferTwo));
// 新增該記錄
list.add(entity);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
return list;
}
/**
* 獲取IP所在的地區資訊
*/
public IpLocation getIpLocation(String ip) {
IpLocation location = new IpLocation();
location.setCountry(this.getCountry(ip));
location.setArea(this.getArea(ip));
return location;
}
/**
* 根據IP地區偏移量,獲取IP資訊
*
* @param offset
* @return
*/
private IpLocation getIpLocation(long offset) {
try {
// 跳過4位元組IP
randomAccessFile.seek(offset + 4);
// 讀取第一個位元組,判斷是否是標識位元組
byte result = randomAccessFile.readByte();
if (result == REDIRECT_MODE_ONE) {
// 讀取國家偏移量
long countryOffset = ReadUtils.readLongByThree(
randomAccessFile, bufferOne);
// 跳轉至偏移處
randomAccessFile.seek(countryOffset);
// 再次檢查識別符號
result = randomAccessFile.readByte();
if (result == REDIRECT_MODE_TWO) {
ipLocation.setCountry(ReadUtils.readString(
randomAccessFile, ReadUtils.readLongByThree(
randomAccessFile, bufferOne), buffer));
randomAccessFile.seek(countryOffset + 4);
} else {
ipLocation.setCountry(ReadUtils.readString(
randomAccessFile, countryOffset, buffer));
}
// 讀取地區識別符號
ipLocation.setArea(this.readArea(randomAccessFile
.getFilePointer()));
} else if (result == REDIRECT_MODE_TWO) {
ipLocation.setCountry(ReadUtils.readString(randomAccessFile,
ReadUtils.readLongByThree(randomAccessFile, bufferOne),
buffer));
ipLocation.setArea(this.readArea(offset + 8));
} else {
ipLocation.setCountry(ReadUtils.readString(randomAccessFile,
randomAccessFile.getFilePointer() - 1, buffer));
ipLocation.setArea(this.readArea(randomAccessFile
.getFilePointer()));
}
return ipLocation;
} catch (Exception e) {
return null;
}
}
/**
* 根據IP地區偏移量,獲取IP資訊
*
* @param offset
* @return
*/
private IpLocation getIpLocation(int offset) {
// 跳過4位元組IP
mappedByteBuffer.position(offset + 4);
// 讀取第一個位元組,判斷是否是標識字元
byte result = mappedByteBuffer.get();
if (result == REDIRECT_MODE_ONE) {
// 讀取國家偏移量
int countryOffset = ReadUtils.readIntByThree(mappedByteBuffer);
// 跳轉至偏移處
mappedByteBuffer.position(countryOffset);
// 再次檢查識別符號
result = mappedByteBuffer.get();
if (result == REDIRECT_MODE_TWO) {
ipLocation.setCountry(ReadUtils.readString(mappedByteBuffer,
ReadUtils.readIntByThree(mappedByteBuffer), buffer));
mappedByteBuffer.position(countryOffset + 4);
} else {
ipLocation.setCountry(ReadUtils.readString(mappedByteBuffer,
countryOffset, buffer));
}
// 設定地區標識
ipLocation.setArea(this.readArea(mappedByteBuffer.position()));
} else if (result == REDIRECT_MODE_TWO) {
ipLocation.setCountry(ReadUtils.readString(mappedByteBuffer,
ReadUtils.readIntByThree(mappedByteBuffer), buffer));
ipLocation.setArea(this.readArea(offset + 8));
} else {
ipLocation.setCountry(ReadUtils.readString(mappedByteBuffer,
mappedByteBuffer.position() - 1, buffer));
ipLocation.setArea(this.readArea(mappedByteBuffer.position()));
}
return ipLocation;
}
/**
* 獲取國家名稱字串
*
* @return
*/
public String getCountry(String ip) {
return this.getCountry(ConvertUtils.getIpArray(ip));
}
/**
* 獲取國家地區
*
* @param ip
* @return
*/
public String getCountry(byte[] ip) {
// 檢測IP地址檔案是否正常
if (randomAccessFile == null) {
return Message.BAD_IP_FILE;
}
// 儲存IP,轉IP位元組陣列為字串
String ipStr = ConvertUtils.getIpString(ip);
// 先從cache中檢查ip,若沒有在檢測檔案
if (cache.containsKey(ipStr)) {
IpLocation ipLocation = cache.get(ipStr);
return ipLocation.getCountry();
} else {
IpLocation ipLocation = this.getIpLocation(ip);
cache.put(ipStr, ipLocation.getCopy());
return ipLocation.getCountry();
}
}
/**
* 根據IP搜尋IP檔案
*
* @param ip
* @return
*/
public IpLocation getIpLocation(byte[] ip) {
IpLocation location = null;
long offset = this.getLocateIp(ip);
if (offset != -1) {
location = this.getIpLocation(offset);
}
if (location == null) {
location = new IpLocation();
location.setCountry(Message.UNKNOW_COUNTRY);
location.setArea(Message.UNKNOW_AREA);
}
return location;
}
/**
* 根據IP內容,定位IP地址所在的國家,返回一個偏移量
*
* @param ip
* @return
*/
public long getLocateIp(byte[] ip) {
long m = 0;
int n;
ReadUtils.readIp(randomAccessFile, begin, bufferTwo);
n = ReadUtils.compareIp(ip, bufferTwo);
if (n == 0)
return begin;
else if (n < 0)
return -1;
// 二分查詢法查詢IP
for (long i = begin, j = end; i < j;) {
m = this.getMiddleOffset(i, j);
ReadUtils.readIp(randomAccessFile, m, bufferTwo);
n = ReadUtils.compareIp(ip, bufferTwo);
if (n > 0) {
i = m;
} else if (n < 0) {
if (m == j) {
j -= IP_RECORD_LENGTH;
m = j;
} else {
j = m;
}
} else {
return ReadUtils.readLongByThree(randomAccessFile, m + 4,
bufferOne);
}
}
m = ReadUtils.readLongByThree(randomAccessFile, m + 4, bufferOne);
ReadUtils.readIp(randomAccessFile, m, bufferTwo);
n = ReadUtils.compareIp(ip, bufferTwo);
if (n <= 0)
return m;
else
return -1;
}
/**
* 根據IP位元組陣列獲取地區名稱
*
* @param ip
* @return
*/
private String getArea(byte[] ip) {
// 檢查IP檔案是否正常
if (randomAccessFile == null)
return Message.BAD_IP_FILE;
// 儲存IP,轉換位元組陣列IP為字串
String ipStr = ConvertUtils.getIpString(ip);
// 現在cache中搜索結果,若沒有,再從檔案中查詢
if (cache.containsKey(ipStr)) {
IpLocation location = cache.get(ipStr);
return location.getArea();
} else {
IpLocation location = this.getIpLocation(ip);
cache.put(ipStr, location.getCopy());
return location.getArea();
}
}
/**
* 根據IP獲取地區名稱
*
* @param ip
* @return
*/
private String getArea(String ip) {
return this.getArea(ConvertUtils.getIpArray(ip));
}
/**
* 從offset位置讀取地區資訊
*
* @param offset
* @return
*/
private String readArea(long offset) {
try {
randomAccessFile.seek(offset);
byte result = randomAccessFile.readByte();
if (result == REDIRECT_MODE_ONE || result == REDIRECT_MODE_TWO) {
long areaOffset = ReadUtils.readLongByThree(randomAccessFile,
offset + 1, bufferOne);
if (areaOffset == 0)
return Message.UNKNOW_AREA;
else
return ReadUtils.readString(randomAccessFile, areaOffset,
buffer);
} else {
return ReadUtils.readString(randomAccessFile, offset, buffer);
}
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
private String readArea(int offset) {
mappedByteBuffer.position(offset);
byte result = mappedByteBuffer.get();
if (result == REDIRECT_MODE_ONE || result == REDIRECT_MODE_TWO) {
int areaOffset = ReadUtils.readIntByThree(mappedByteBuffer);
if (areaOffset == 0)
return Message.UNKNOW_AREA;
else
return ReadUtils.readString(mappedByteBuffer, areaOffset,
buffer);
} else {
return ReadUtils.readString(mappedByteBuffer, offset, buffer);
}
}
/**
* 獲取begin和end中間偏移量
*
* @param begin
* @param end
* @return
*/
private long getMiddleOffset(long begin, long end) {
long middle = (end - begin) / IP_RECORD_LENGTH;
middle >>= 1;
if (middle == 0)
middle = 1;
return begin + middle * IP_RECORD_LENGTH;
}
}
7.測試程式
package com.test.ip;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import com.test.ip.viewer.IpViewer;
public class Test {
public static void main(String[] args){
String ip = "63.251.90.8";
IpViewer ipViewer = new IpViewer();
System.out.println(ipViewer.getIpLocation(ip).getCountry()+":"+ipViewer.getIpLocation(ip).getArea());
}
}
原文:https://blog.csdn.net/aleyns/article/details/78849835