⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ipseeker.java

📁 天乙虚拟社区8.05版本。只支持Mysql
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
package com.laoer.bbscs.comm;

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.Hashtable;
import java.util.List;
import java.util.StringTokenizer;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.io.*;
//import org.springframework.core.io.*;

/**
 * <p>
 * Title: IP查询
 * </p>
 *
 * <p>
 * Description:
 * </p>
 *
 * <p>
 * Copyright: Copyright (c) 2006
 * </p>
 *
 * <p>
 * Company:
 * </p>
 *
 * @author not attributable
 * @version 1.0
 */
public class IPSeeker {

	/**
	 * <pre>
	 *    用来封装ip相关信息,目前只有两个字段,ip所在的国家和地区
	 * </pre>
	 *
	 * @author 马若劼
	 */
	private class IPLocation {
		public String country;

		public String area;

		public IPLocation() {
			country = area = "";
		}

		public IPLocation getCopy() {
			IPLocation ret = new IPLocation();
			ret.country = country;
			ret.area = area;
			return ret;
		}
	}

	// 一些固定常量,比如记录长度等等
	private static final int IP_RECORD_LENGTH = 7;

	private static final byte REDIRECT_MODE_1 = 0x01;

	private static final byte REDIRECT_MODE_2 = 0x02;

	// Log对象
	private static Log log = LogFactory.getLog(IPSeeker.class);

	// 用来做为cache,查询一个ip时首先查看cache,以减少不必要的重复查找
	private Hashtable<String, IPLocation> ipCache;

	// 随机文件访问类
	private RandomAccessFile ipFile;

	// 内存映射文件
	private MappedByteBuffer mbb;

	// 单一模式实例
	// private static IPSeeker instance = new IPSeeker();
	// 起始地区的开始和结束的绝对偏移
	private long ipBegin, ipEnd;

	// 为提高效率而采用的临时变量
	private IPLocation loc;

	private byte[] buf;

	private byte[] b4;

	private byte[] b3;

	private static final String IPDATE_FILE_PATH = Constant.ROOTPATH + "/WEB-INF/IPDate/";

	private static final String IPDATE_FILE = "QQWry.Dat";

	/**
	 * 私有构造函数
	 */
	public IPSeeker() {
		ipCache = new Hashtable<String, IPLocation>();
		loc = new IPLocation();
		buf = new byte[100];
		b4 = new byte[4];
		b3 = new byte[3];
		try {
			// ClassPathResource cpr = new ClassPathResource("/" + IPDATE_FILE);
			// System.out.println(cpr.getFile());
			ipFile = new RandomAccessFile(IPDATE_FILE_PATH + IPDATE_FILE, "r");
			// ipFile = new RandomAccessFile(cpr.getFile(), "r");
		} catch (FileNotFoundException e) {
			// 如果找不到这个文件,再尝试再当前目录下搜索,这次全部改用小写文件名
			// 因为有些系统可能区分大小写导致找不到ip地址信息文件
			String filename = new File(IPDATE_FILE_PATH + IPDATE_FILE).getName().toLowerCase();
			File[] files = new File(IPDATE_FILE_PATH).listFiles();
			for (int i = 0; i < files.length; i++) {
				if (files[i].isFile()) {
					if (files[i].getName().toLowerCase().equals(filename)) {
						try {
							ipFile = new RandomAccessFile(files[i], "r");
						} catch (FileNotFoundException e1) {
							log.error("IP地址信息文件没有找到,IP显示功能将无法使用");
							ipFile = null;
						}
						break;
					}
				}
			}
		}
		// 如果打开文件成功,读取文件头信息
		if (ipFile != null) {
			try {
				ipBegin = readLong4(0);
				ipEnd = readLong4(4);
				if (ipBegin == -1 || ipEnd == -1) {
					ipFile.close();
					ipFile = null;
				}
			} catch (IOException e) {
				log.error("IP地址信息文件格式有错误,IP显示功能将无法使用");
				ipFile = null;
			}
		}
	}

	/**
	 * @return 单一实例
	 */
	// public static IPSeeker getInstance() {
	// return instance;
	// }
	/**
	 * 给定一个地点的不完全名字,得到一系列包含s子串的IP范围记录
	 *
	 * @param s
	 *            地点子串
	 * @return 包含IPEntry类型的List
	 */
	public List getIPEntriesDebug(String s) {
		List<IPEntry> ret = new ArrayList<IPEntry>();
		long endOffset = ipEnd + 4;
		for (long offset = ipBegin + 4; offset <= endOffset; offset += IP_RECORD_LENGTH) {
			// 读取结束IP偏移
			long temp = readLong3(offset);
			// 如果temp不等于-1,读取IP的地点信息
			if (temp != -1) {
				IPLocation loc = getIPLocation(temp);
				// 判断是否这个地点里面包含了s子串,如果包含了,添加这个记录到List中,如果没有,继续
				if (loc.country.indexOf(s) != -1 || loc.area.indexOf(s) != -1) {
					IPEntry entry = new IPEntry();
					entry.country = loc.country;
					entry.area = loc.area;
					// 得到起始IP
					readIP(offset - 4, b4);
					entry.beginIp = getIpStringFromBytes(b4);
					// 得到结束IP
					readIP(temp, b4);
					entry.endIp = getIpStringFromBytes(b4);
					// 添加该记录
					ret.add(entry);
				}
			}
		}
		return ret;
	}

	/**
	 * 给定一个地点的不完全名字,得到一系列包含s子串的IP范围记录
	 *
	 * @param s
	 *            地点子串
	 * @return 包含IPEntry类型的List
	 */
	public List getIPEntries(String s) {
		List<IPEntry> ret = new ArrayList<IPEntry>();
		try {
			// 映射IP信息文件到内存中
			if (mbb == null) {
				FileChannel fc = ipFile.getChannel();
				mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, ipFile.length());
				mbb.order(ByteOrder.LITTLE_ENDIAN);
			}

			int endOffset = (int) ipEnd;
			for (int offset = (int) ipBegin + 4; offset <= endOffset; offset += IP_RECORD_LENGTH) {
				int temp = readInt3(offset);
				if (temp != -1) {
					IPLocation loc = getIPLocation(temp);
					// 判断是否这个地点里面包含了s子串,如果包含了,添加这个记录到List中,如果没有,继续
					if (loc.country.indexOf(s) != -1 || loc.area.indexOf(s) != -1) {
						IPEntry entry = new IPEntry();
						entry.country = loc.country;
						entry.area = loc.area;
						// 得到起始IP
						readIP(offset - 4, b4);
						entry.beginIp = getIpStringFromBytes(b4);
						// 得到结束IP
						readIP(temp, b4);
						entry.endIp = getIpStringFromBytes(b4);
						// 添加该记录
						ret.add(entry);
					}
				}
			}
		} catch (IOException e) {
			log.error(e.getMessage());
		}
		return ret;
	}

	/**
	 * 从内存映射文件的offset位置开始的3个字节读取一个int
	 *
	 * @param offset
	 * @return
	 */
	private int readInt3(int offset) {
		mbb.position(offset);
		return mbb.getInt() & 0x00FFFFFF;
	}

	/**
	 * 从内存映射文件的当前位置开始的3个字节读取一个int
	 *
	 * @return
	 */
	private int readInt3() {
		return mbb.getInt() & 0x00FFFFFF;
	}

	/**
	 * 根据IP得到国家名
	 *
	 * @param ip
	 *            ip的字节数组形式
	 * @return 国家名字符串
	 */
	public String getCountry(byte[] ip) {
		// 检查ip地址文件是否正常
		if (ipFile == null) {
			// return LumaQQ.getString("bad.ip.file");
			return "bad.ip.file";
		}
		// 保存ip,转换ip字节数组为字符串形式
		String ipStr = getIpStringFromBytes(ip);
		// 先检查cache中是否已经包含有这个ip的结果,没有再搜索文件
		if (ipCache.containsKey(ipStr)) {
			IPLocation loc = (IPLocation) ipCache.get(ipStr);
			return loc.country;
		} else {
			IPLocation loc = getIPLocation(ip);
			ipCache.put(ipStr, loc.getCopy());
			return loc.country;
		}
	}

	/**
	 * 根据IP得到国家名
	 *
	 * @param ip
	 *            IP的字符串形式
	 * @return 国家名字符串
	 */
	public String getCountry(String ip) {
		return getCountry(getIpByteArrayFromString(ip));
	}

	/**
	 * 根据IP得到地区名
	 *
	 * @param ip
	 *            ip的字节数组形式
	 * @return 地区名字符串
	 */
	public String getArea(byte[] ip) {
		// 检查ip地址文件是否正常
		if (ipFile == null) {
			// return LumaQQ.getString("bad.ip.file");
			return "bad.ip.file";
		}
		// 保存ip,转换ip字节数组为字符串形式
		String ipStr = getIpStringFromBytes(ip);
		// 先检查cache中是否已经包含有这个ip的结果,没有再搜索文件
		if (ipCache.containsKey(ipStr)) {
			IPLocation loc = (IPLocation) ipCache.get(ipStr);
			return loc.area;
		} else {
			IPLocation loc = getIPLocation(ip);
			ipCache.put(ipStr, loc.getCopy());
			return loc.area;
		}
	}

	/**
	 * 根据IP得到地区名
	 *
	 * @param ip
	 *            IP的字符串形式
	 * @return 地区名字符串
	 */
	public String getArea(String ip) {
		return getArea(getIpByteArrayFromString(ip));
	}

	/**
	 * 根据ip搜索ip信息文件,得到IPLocation结构,所搜索的ip参数从类成员ip中得到
	 *
	 * @param ip
	 *            要查询的IP
	 * @return IPLocation结构
	 */
	private IPLocation getIPLocation(byte[] ip) {
		IPLocation info = null;
		long offset = locateIP(ip);
		if (offset != -1) {
			info = getIPLocation(offset);
		}
		if (info == null) {
			info = new IPLocation();
			// info.country = LumaQQ.getString("unknown.country");
			// info.area = LumaQQ.getString("unknown.area");
			info.country = "";
			info.area = "";
		}
		return info;
	}

	/**
	 * 从offset位置读取4个字节为一个long,因为java为big-endian格式,所以没办法 用了这么一个函数来做转换
	 *
	 * @param offset
	 * @return 读取的long值,返回-1表示读取文件失败
	 */
	private long readLong4(long offset) {
		long ret = 0;
		try {
			ipFile.seek(offset);
			ret |= (ipFile.readByte() & 0xFF);
			ret |= ((ipFile.readByte() << 8) & 0xFF00);
			ret |= ((ipFile.readByte() << 16) & 0xFF0000);
			ret |= ((ipFile.readByte() << 24) & 0xFF000000);
			return ret;
		} catch (IOException e) {
			return -1;
		}
	}

	/**
	 * 从offset位置读取3个字节为一个long,因为java为big-endian格式,所以没办法 用了这么一个函数来做转换
	 *
	 * @param offset
	 *            整数的起始偏移
	 * @return 读取的long值,返回-1表示读取文件失败
	 */
	private long readLong3(long offset) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -