Blue Dream

记录成长的每一个脚印,写下漫长的程序人生
  首页  :: 订阅 订阅  :: 管理

C#如何读取QQ纯真IP数据库

Posted on 2006-08-17 09:25  Dennis  阅读(1647)  评论(0编辑  收藏  举报

C#如何读取QQ纯真IP数据库

使用方法:

例子:
BDQQ.Data.QQWry qq=new BDQQ.Data.QQWry("d:\\QQWry.Dat");
BDQQ.Data.IPLocation ip=qq.SearchIPLocation("127.0.0.1");//这里添写IP地址
Console.WriteLine(ip.country);//国家
Console.WriteLine(ip.area);//地区

以下是类文件



//根据LumaQQ改写而成.

using System;
using System.IO;
using System.Text;
 
namespace BDQQ.Data
{
    /**//// <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;
 
        //IP地址对象
        #region IP地址对象
            /**//// <summary>
            /// IP对象
            /// </summary>
            #endregion
            private IPLocation loc;
 
        //存储文本内容
        #region 存储文本内容
            /**//// <summary>
            /// 存储文本内容
            /// </summary>
            #endregion
            private byte[] buf;
 
        //存储3字节
        #region 存储3字节
            /**//// <summary>
            /// 存储3字节
            /// </summary>
            #endregion
            private byte[] b3;
 
        //存储4字节
        #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();
            }


        //根据IP地址搜索
        #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 "";
            }


        //查找IP地址所在的绝对偏移量
        #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;
            }


        //读出4字节的IP地址
        #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;
            }


        //比较IP地址是否相同
        #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;
            }


        //根据当前位置读取4字节
        #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;
            }


        //根据当前位置,读取3字节
        #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;
                   }


        //从当前位置读取3字节
        #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;
            }


        //取得begin和end之间的偏移量
        #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;
        }
    }
}