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

📄 ipseeker.java

📁 一个jsp写的bbs
💻 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.*;

/**
 * <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 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();
    loc = new IPLocation();
    buf = new byte[100];
    b4 = new byte[4];
    b3 = new byte[3];
    try {
      ipFile = new RandomAccessFile(IPDATE_FILE_PATH + IPDATE_FILE, "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 ret = new ArrayList();
    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 ret = new ArrayList();
    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) {
    long ret = 0;
    try {
      ipFile.seek(offset);
      ipFile.readFully(b3);
      ret |= (b3[0] & 0xFF);
      ret |= ( (b3[1] << 8) & 0xFF00);
      ret |= ( (b3[2] << 16) & 0xFF0000);
      return ret;
    }
    catch (IOException e) {
      return -1;
    }
  }

  /**
   * 从当前位置读取3个字节转换成long
   * @return 读取的long值,返回-1表示读取文件失败
   */

⌨️ 快捷键说明

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