查询纯真数据库的方法

来源:互联网 发布:阿里妈妈淘宝联盟登录 编辑:程序博客网 时间:2024/06/11 23:25

参考于LumaQQ

/// <summary>
 /// QQWry 的摘要说明。
 /// </summary>
 public class QQWry
 {
  #region 第一种模式
  /// <summary>
  /// 第一种模式
  /// </summary>
  #endregion
  private const byte REDIRECT_MODE_1  = 0x01;

  #region 第二种模式
  /// <summary>
  /// 第二种模式
  /// </summary>
  #endregion
  private const byte REDIRECT_MODE_2  = 0x02;

  #region 每条记录长度
  /// <summary>
  /// 每条记录长度
  /// </summary>
  #endregion  
  private const int IP_RECORD_LENGTH  = 7;

  #region 数据库文件
  /// <summary>
  /// 文件对象
  /// </summary>
  #endregion  
  private FileStream ipFile;

  private const string unCountry = "未知国家";
  private const string unArea = "未知地区";

  #region 索引开始位置
  /// <summary>
  /// 索引开始位置
  /// </summary>
  #endregion
  private long ipBegin;

  #region 索引结束位置
  /// <summary>
  /// 索引结束位置
  /// </summary>
  #endregion
  private long ipEnd;

  #region IP地址对象
  /// <summary>
  /// IP对象
  /// </summary>
  #endregion
  private IPLocation loc;

  #region 存储文本内容
  /// <summary>
  /// 存储文本内容
  /// </summary>
  #endregion
  private byte[] buf;

  #region 存储3字节
  /// <summary>
  /// 存储3字节
  /// </summary>
  #endregion
  private byte[] b3;

  #region 存储4字节
  /// <summary>
  /// 存储4字节IP地址
  /// </summary>
  #endregion
  private byte[] b4;

  #region 构造函数
  /// <summary>
  /// 构造函数
  /// </summary>
  /// <param name="ipfile">IP数据库文件绝对路径</param>
  #endregion
  public QQWry( string ipfile )
  {   
   buf = new byte[100];
   b3 = new byte[3];
   b4 = new byte[4];   
   try
   {
    ipFile = new FileStream( ipfile,FileMode.Open );
   }
   catch( Exception ex )
   {
    throw new Exception( ex.Message );
   }   
   ipBegin = readLong4(0);
   ipEnd = readLong4(4);
   loc = new IPLocation();
  }


  #region 根据IP地址搜索
  /// <summary>
  /// 搜索IP地址搜索
  /// </summary>
  /// <param name="ip"></param>
  /// <returns></returns>
  #endregion
  public IPLocation SearchIPLocation( string ip )
  {
   //将字符IP转换为字节
   string[] ipSp = ip.Split('.');
   if( ipSp.Length != 4 )
   {
    throw new ArgumentOutOfRangeException( "不是合法的IP地址!" );
   }
   byte[] IP = new byte[4];
   for( int i = 0; i < IP.Length ; i++ )
   {
    IP[i] = (byte)(Int32.Parse( ipSp[i] ) & 0xFF) ;
   }

   IPLocation local = null;
   long offset = locateIP( IP );

   if( offset != -1 )
   {
    local = getIPLocation( offset );
   }

   if( local == null )
   {
    local = new IPLocation();
    local.area = unArea;
    local.country = unCountry;
   }
   return local;
  }


  #region 取得具体信息
  /// <summary>
  /// 取得具体信息
  /// </summary>
  /// <param name="offset"></param>
  /// <returns></returns>
  #endregion
  private IPLocation getIPLocation( long offset )
  {
   ipFile.Position = offset + 4;
   //读取第一个字节判断是否是标志字节
   byte one = (byte)ipFile.ReadByte();
   if( one == REDIRECT_MODE_1 )
   {
    //第一种模式
    //读取国家偏移
    long countryOffset = readLong3();
    //转至偏移处
    ipFile.Position = countryOffset;
    //再次检查标志字节
    byte b = (byte)ipFile.ReadByte();
    if( b == REDIRECT_MODE_2 )
    {
     loc.country = readString( readLong3() );
     ipFile.Position = countryOffset + 4;
    }
    else
     loc.country = readString( countryOffset );

    //读取地区标志
    loc.area = readArea( ipFile.Position );

   }
   else if( one == REDIRECT_MODE_2 )
   {
    //第二种模式
    loc.country = readString( readLong3() );
    loc.area = readArea( offset + 8 );
   }
   else
   {
    //普通模式
    loc.country = readString( --ipFile.Position );
    loc.area = readString( ipFile.Position );
   }
   return loc;
  }


  #region 取得地区信息
  /// <summary>
  /// 读取地区名称
  /// </summary>
  /// <param name="offset"></param>
  /// <returns></returns>
  #endregion
  private string readArea( long offset )
  {
   ipFile.Position = offset;
   byte one = (byte)ipFile.ReadByte();
   if( one == REDIRECT_MODE_1 || one == REDIRECT_MODE_2 )
   {
    long areaOffset = readLong3( offset + 1 );
    if( areaOffset == 0 )
     return unArea;
    else
    {
     return readString( areaOffset );
    }
   }
   else
   {
    return readString( offset );
   }
  }


  #region 读取字符串
  /// <summary>
  /// 读取字符串
  /// </summary>
  /// <param name="offset"></param>
  /// <returns></returns>
  #endregion
  private string readString( long offset )
  {
   ipFile.Position = offset;
   int i = 0;
   for(i = 0, buf[i]=(byte)ipFile.ReadByte();buf[i] != (byte)(0);buf[++i]=(byte)ipFile.ReadByte());
           
   if( i > 0 )
    return Encoding.Default.GetString( buf,0,i );
   else
    return "";
  }


  #region 查找IP地址所在的绝对偏移量
  /// <summary>
  /// 查找IP地址所在的绝对偏移量
  /// </summary>
  /// <param name="ip"></param>
  /// <returns></returns>
  #endregion
  private long locateIP( byte[] ip )
  {
   long m = 0;
   int r;

   //比较第一个IP项
   readIP( ipBegin, b4 );
   r = compareIP( ip,b4);
   if( r == 0 )
    return ipBegin;
   else if( r < 0 )
    return -1;
   //开始二分搜索
   for( long i = ipBegin,j=ipEnd; i<j; )
   {
    m = this.getMiddleOffset( i,j );
    readIP( m,b4 );
    r = compareIP( ip,b4 );
    if( r > 0 )
     i = m;
    else if( r < 0 )
    {
     if( m == j )
     {
      j -= IP_RECORD_LENGTH;
      m = j;
     }
     else
     {
      j = m;
     }
    }
    else
     return readLong3( m+4 );
   }
   m = readLong3( m+4 );
   readIP( m,b4 );
   r = compareIP( ip,b4 );
   if( r <= 0 )
    return m;
   else
    return -1;
  }


  #region 读出4字节的IP地址
  /// <summary>
  /// 从当前位置读取四字节,此四字节是IP地址
  /// </summary>
  /// <param name="offset"></param>
  /// <param name="ip"></param>
  #endregion
  private void readIP( long offset, byte[] ip )
  {
   ipFile.Position = offset;
   ipFile.Read( ip,0,ip.Length );
   byte tmp = ip[0];
   ip[0] = ip[3];
   ip[3] = tmp;
   tmp = ip[1];
   ip[1] = ip[2];
   ip[2] = tmp;
  }


  #region 比较IP地址是否相同
  /// <summary>
  /// 比较IP地址是否相同
  /// </summary>
  /// <param name="ip"></param>
  /// <param name="beginIP"></param>
  /// <returns>0:相等,1:ip大于beginIP,-1:小于</returns>
  #endregion
  private int compareIP( byte[] ip, byte[] beginIP )
  {
   for( int i = 0; i < 4; i++ )
   {
    int r = compareByte( ip[i],beginIP[i] );
    if( r != 0 )
     return r;
   }
   return 0;
  }


  #region 比较两个字节是否相等
  /// <summary>
  /// 比较两个字节是否相等
  /// </summary>
  /// <param name="bsrc"></param>
  /// <param name="bdst"></param>
  /// <returns></returns>
  #endregion
  private int compareByte( byte bsrc, byte bdst )
  {
   if( ( bsrc&0xFF ) > ( bdst&0xFF ) )
    return 1;
   else if( (bsrc ^ bdst) == 0 )
    return 0;
   else
    return -1;
  }


  #region 根据当前位置读取4字节
  /// <summary>
  /// 从当前位置读取4字节,转换为长整型
  /// </summary>
  /// <param name="offset"></param>
  /// <returns></returns>
  #endregion
  private long readLong4( long offset )
  {
   long ret = 0;
   ipFile.Position = offset;
   ret |= ( ipFile.ReadByte() & 0xFF );
   ret |= ( ( ipFile.ReadByte() << 8 ) & 0xFF00 );
   ret |= ( ( ipFile.ReadByte() << 16 ) & 0xFF0000 );
   ret |= ( ( ipFile.ReadByte() << 24 ) & 0xFF000000 );
   return ret;
  }


  #region 根据当前位置,读取3字节
  /// <summary>
  /// 根据当前位置,读取3字节
  /// </summary>
  /// <param name="offset"></param>
  /// <returns></returns>
  #endregion
  private long readLong3( long offset )
  {
   long ret = 0;
   ipFile.Position = offset;
   ret |= ( ipFile.ReadByte() & 0xFF );
   ret |= ( (ipFile.ReadByte() << 8 ) & 0xFF00 );
   ret |= ( (ipFile.ReadByte() << 16 ) & 0xFF0000 );
   return ret;
  }


  #region 从当前位置读取3字节
  /// <summary>
  /// 从当前位置读取3字节
  /// </summary>
  /// <returns></returns>
  #endregion
  private long readLong3()
  {
   long ret = 0;   
   ret |= ( ipFile.ReadByte() & 0xFF );
   ret |= ( (ipFile.ReadByte() << 8 ) & 0xFF00 );
   ret |= ( (ipFile.ReadByte() << 16 ) & 0xFF0000 );
   return ret;
  }


  #region 取得begin和end之间的偏移量
  /// <summary>
  /// 取得begin和end中间的偏移
  /// </summary>
  /// <param name="begin"></param>
  /// <param name="end"></param>
  /// <returns></returns>
  #endregion
  private long getMiddleOffset( long begin, long end )
  {
   long records = ( end - begin ) / IP_RECORD_LENGTH;
   records >>= 1;
   if( records == 0 )
    records = 1;
   return begin + records * IP_RECORD_LENGTH;
  }
 } //class QQWry

 public 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;
  }
 }

原创粉丝点击