package com.jd.train.service.util;
import com.jd.common.util.StringUtils;
import com.jd.train.manager.util.impl.HttpClientUtilManagerImpl;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
public class IPParser {
private final Logger log = Logger.getLogger(IPParser.class);
private String url; //ip查询请求地址
private String dbPath; //本地IP数据库地址
private String country, localStr;
private long IPN;
private int recordCount, countryFlag;
private long rangE, rangB, offSet, startIP, endIP, firstStartIP,lastStartIP, endIPOff;
private RandomAccessFile fis;
private byte[] buff;
private long B2L(byte[] b) {
long ret = 0;
for (int i = 0; i < b.length; i++) {
long t = 1L;
for (int j = 0; j < i; j++)
t = t * 256L;
ret += ((b[i] < 0) ? 256 + b[i] : b[i]) * t;
}
return ret;
}
private long ipToInt(String ip) {
String[] arr = ip.split("\\.");
long ret = 0;
for (int i = 0; i < arr.length; i++) {
long l = 1;
for (int j = 0; j < i; j++)
l *= 256;
try {
ret += Long.parseLong(arr[arr.length - i - 1]) * l;
} catch (Exception e) {
ret += 0;
}
}
return ret;
}
private void seek(String ip) throws Exception {
IPN = ipToInt(ip);
fis = new RandomAccessFile(dbPath, "r");
buff = new byte[4];
fis.seek(0);
fis.read(buff);
firstStartIP = B2L(buff);
fis.read(buff);
lastStartIP = B2L(buff);
recordCount = (int) ((lastStartIP - firstStartIP) / 7);
if (recordCount <= 1) {
localStr = country = "未知";
throw new Exception();
}
rangB = 0;
rangE = recordCount;
long RecNo;
do {
RecNo = (rangB + rangE) / 2;
getStartIP(RecNo);
if (IPN == startIP) {
rangB = RecNo;
break;
}
if (IPN > startIP)
rangB = RecNo;
else
rangE = RecNo;
} while (rangB < rangE - 1);
getStartIP(rangB);
getEndIP();
getCountry(IPN);
fis.close();
}
private String getFlagStr(long OffSet) throws IOException {
int flag = 0;
do {
fis.seek(OffSet);
buff = new byte[1];
fis.read(buff);
flag = (buff[0] < 0) ? 256 + buff[0] : buff[0];
if (flag == 1 || flag == 2) {
buff = new byte[3];
fis.read(buff);
if (flag == 2) {
countryFlag = 2;
endIPOff = OffSet - 4;
}
OffSet = B2L(buff);
} else
break;
} while (true);
if (OffSet < 12) {
return "";
} else {
fis.seek(OffSet);
return getStr();
}
}
private String getStr() throws IOException {
long l = fis.length();
ByteArrayOutputStream byteout = new ByteArrayOutputStream();
byte c = fis.readByte();
do {
byteout.write(c);
c = fis.readByte();
} while (c != 0 && fis.getFilePointer() < l);
return byteout.toString();
}
private void getCountry(long ip) throws IOException {
if (countryFlag == 1 || countryFlag == 2) {
country = getFlagStr(endIPOff + 4);
if (countryFlag == 1) {
localStr = getFlagStr(fis.getFilePointer());
if (IPN >= ipToInt("255.255.255.0")
&& IPN <= ipToInt("255.255.255.255")) {
localStr = getFlagStr(endIPOff + 21);
country = getFlagStr(endIPOff + 12);
}
} else {
localStr = getFlagStr(endIPOff + 8);
}
} else {
country = getFlagStr(endIPOff + 4);
localStr = getFlagStr(fis.getFilePointer());
}
}
private long getEndIP() throws IOException {
fis.seek(endIPOff);
buff = new byte[4];
fis.read(buff);
endIP = B2L(buff);
buff = new byte[1];
fis.read(buff);
countryFlag = (buff[0] < 0) ? 256 + buff[0] : buff[0];
return endIP;
}
private long getStartIP(long RecNo) throws IOException {
offSet = firstStartIP + RecNo * 7;
fis.seek(offSet);
buff = new byte[4];
fis.read(buff);
startIP = B2L(buff);
buff = new byte[3];
fis.read(buff);
endIPOff = B2L(buff);
return startIP;
}
private String getUserIp(HttpServletRequest request) {
String ip = CodesUtil.getIpAddr(request);
if (ip != null && ip.indexOf(",") > 0) {
log.info("取到客户多个ip1====================" + ip);
String[] arr = ip.split(",");
ip = arr[arr.length - 1].trim();//有多个ip时取最后一个ip
log.info("取到客户多个ip2====================" + ip);
}
return ip;
}
private String findCity(HttpServletRequest request , String ipStr) {
if(null == request && StringUtils.isEmpty(ipStr)){
log.info("IPParser,findIpAddr(), request and ip is empty !");
return null;
}
String ip = ipStr;
if(request != null){
ip = getUserIp(request);
}
if(StringUtils.isEmpty(ip)){
log.info("IPParser,findIpAddr(), ip is empty !");
return null;
}
String result;
String location;
try {
seek(ip.trim());
} catch (Exception e) {
log.error("IPParser,findIpAddr() error ! " + e);
}
location = country;
//查不到1
if (StringUtils.isEmpty(location)) {
log.info("IPParser,findIpAddr(), location is empty ! Trying remote interface ...");
location = findIpAddrRemote(ip);
if (StringUtils.isEmpty(location)) {
log.info("IPParser,findIpAddr(), location is empty !");
return null;
}
}
//查不到2
location = location.trim();
if (location.length() == 0) {
log.info("IPParser,findIpAddr(), location length is 0 ! Trying remote interface ...");
location = findIpAddrRemote(ip);
if (StringUtils.isEmpty(location)) {
log.info("IPParser,findIpAddr(), location is empty !");
return null;
}
if (location.length() == 0) {
log.info("IPParser,findIpAddr(), location length is 0 !");
return null;
}
}
//查不到3
if (location.contains("未知")) {
log.info("IPParser,findIpAddr(), location is not found ! Trying remote interface ...");
location = findIpAddrRemote(ip);
if (StringUtils.isEmpty(location)) {
log.info("IPParser,findIpAddr(), location is empty !");
return null;
}
if (location.contains("未知")) {
log.info("IPParser,findIpAddr(), location is not found !");
return null;
}
}
int cityIndex = location.indexOf("市");
int cityIndex2 = location.indexOf("市", cityIndex + 1);
int provinceIndex = location.indexOf("省");
if (cityIndex > -1 && cityIndex2 == -1) {
if (provinceIndex > -1) {
location = location.substring(provinceIndex + 1, cityIndex);
} else {
location = location.substring(0, cityIndex);
}
}
//处理有2个市的地址
if (cityIndex > -1 && cityIndex2 > -1) {
location = location.substring(cityIndex + 1, cityIndex2);
}
//自治区处理
if (location.contains("宁夏")) {
location = location.replaceAll("宁夏", "");
}
if (location.indexOf("内蒙古") > -1) {
location = location.replaceAll("内蒙古", "");
int districtIndex = location.indexOf("盟");
if (districtIndex > -1) {
location = location.substring(districtIndex + 1, location.length());
}
}
if (location.indexOf("广西") > -1) {
location = location.replaceAll("广西", "");
}
if (location.indexOf("西藏") > -1) {
location = location.replaceAll("西藏", "");
}
if (location.indexOf("新疆") > -1) {
location = location.replaceAll("新疆", "");
int districtIndex = location.indexOf("州");
if (districtIndex > -1) {
location = location.substring(districtIndex + 1, location.length());
}
}
//港澳台处理
if (location.contains("省")) {
location = location.replaceAll("省", "");
}
//其他
if (location.startsWith("清华大学")) {
location = "北京";
}
//去掉CZ88.NET字样,去掉空格
location = location.replaceAll("CZ88.NET", "");
result = location.replaceAll(" ", "");
log.info(ip + " --> " + location);
return result;
}
private String findIpAddrRemote(String ip) {
String result;
HttpClientUtilManagerImpl httpClientUtilManager = new HttpClientUtilManagerImpl();
httpClientUtilManager.setTimeout(1000); //超时时间 1s
String ipXML = httpClientUtilManager.executeHttpRequestString(url + ip, null);
if (ipXML == null) {
log.info("IPParser,findIpAddrRemote(),ipXML is null !");
return null;
}
Document doc;
try {
doc = DocumentHelper.parseText(ipXML.trim());
} catch (DocumentException e) {
log.error("IPParser,findIpAddrRemote() error !" + e);
return null;
}
if (doc == null) {
log.info("IPParser,findIpAddrRemote(),doc is null !");
return null;
}
Element rootElement = doc.getRootElement();
Element productElement = rootElement.element("product");
if (productElement == null) {
log.info("IPParser,findIpAddrRemote(),productElement is null !");
return null;
}
Element element = productElement.element("location");
if (element == null) {
log.info("IPParser,findIpAddrRemote(),element is null !");
return null;
}
result = element.getTextTrim();
return result;
}
/**
* 根据ip获得城市名称
* @param ip
* @return
*/
public String ipToCity(String ip){
return findCity(null , ip);
}
/**
* 根据请求获得城市名称
* @param request
* @return
*/
public String ipToCity(HttpServletRequest request){
return findCity(request, null);
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getDbPath() {
return dbPath;
}
public void setDbPath(String dbPath) {
this.dbPath = dbPath;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getLocalStr() {
return localStr;
}
public void setLocalStr(String localStr) {
this.localStr = localStr;
}
public long getIPN() {
return IPN;
}
public void setIPN(long IPN) {
this.IPN = IPN;
}
public int getRecordCount() {
return recordCount;
}
public void setRecordCount(int recordCount) {
this.recordCount = recordCount;
}
public int getCountryFlag() {
return countryFlag;
}
public void setCountryFlag(int countryFlag) {
this.countryFlag = countryFlag;
}
public long getRangE() {
return rangE;
}
public void setRangE(long rangE) {
this.rangE = rangE;
}
public long getRangB() {
return rangB;
}
public void setRangB(long rangB) {
this.rangB = rangB;
}
public long getOffSet() {
return offSet;
}
public void setOffSet(long offSet) {
this.offSet = offSet;
}
public long getStartIP() {
return startIP;
}
public void setStartIP(long startIP) {
this.startIP = startIP;
}
public long getFirstStartIP() {
return firstStartIP;
}
public void setFirstStartIP(long firstStartIP) {
this.firstStartIP = firstStartIP;
}
public long getLastStartIP() {
return lastStartIP;
}
public void setLastStartIP(long lastStartIP) {
this.lastStartIP = lastStartIP;
}
public long getEndIPOff() {
return endIPOff;
}
public void setEndIPOff(long endIPOff) {
this.endIPOff = endIPOff;
}
public RandomAccessFile getFis() {
return fis;
}
public void setFis(RandomAccessFile fis) {
this.fis = fis;
}
public byte[] getBuff() {
return buff;
}
public void setBuff(byte[] buff) {
this.buff = buff;
}
public static void main(String[] args) throws Exception {
long initUsedMemory = (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory());
long start = System.currentTimeMillis();
IPParser w = new IPParser();
// w.setPath(new File("QQWry2.Dat").getAbsolutePath());
// w.seek("125.10.100.17");
// String ip = "211.161.190.171";
// String ip = "14.192.60.1";
// w.findRequestPhysAddr(ip);
long end = System.currentTimeMillis();
long endUsedMemory = (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory());
System.out.println("time spent:" + (end - start) + " ms");
System.out.println("memory consumes:" + (endUsedMemory - initUsedMemory));
}
}