寂寞部屋
- 关注互联网,关注生活
关注互联网,关注生活
2019年五月
« 4月    
 12345
6789101112
13141516171819
20212223242526
2728293031  
  • 日志总数:553 篇
  • 浏览总量:2,435,534 次
  • 运行天数:619 天
  • 建站时间:2017-9-14
  • 最后更新:2019-4-2

C#读取QQWry.Dat文件实现IP查询

QQ纯真IP库算是IP地址收集较为全的一个IP库,对于IP查询来说这个是不错的选择。下面是如何查询纯真IP库的一个类,使用C#代码。

C#代码
  1. using System;   
  2. using System.Collections.Generic;   
  3. using System.Text;   
  4. using System.IO;   
  5. using System.Web;   
  6. using System.Configuration;   
  7.   
  8. namespace BLL   
  9. {   
  10.     public class IPLocationSearch   
  11.     {   
  12.         private static readonly QQWry qq = new QQWry(ConfigurationManager.AppSettings["ip"] + "qqwry.dat");   
  13.   
  14.         public static IPLocation GetIPLocation(string ip)   
  15.         {   
  16.             return qq.SearchIPLocation(ip);   
  17.         }   
  18.     }   
  19.   
  20.     /*  
  21.     使用方法:  
  22.    
  23.     例子:  
  24.     BDQQ.Data.QQWry qq=new BDQQ.Data.QQWry("d:\\QQWry.Dat");  
  25.     BDQQ.Data.IPLocation ip=qq.SearchIPLocation("127.0.0.1");//这里添写IP地址  
  26.     Console.WriteLine(ip.country);//国家  
  27.     Console.WriteLine(ip.area);//地区  
  28.     */  
  29.   
  30.     //以下是类文件   
  31.     //根据LumaQQ改写而成.   
  32.   
  33.     /**/  
  34.     ///<summary>   
  35.     /// QQWry 的摘要说明。   
  36.     ///</summary>   
  37.     public class QQWry   
  38.     {   
  39.         //第一种模式  
  40.         #region 第一种模式   
  41.         /**/  
  42.         ///<summary>   
  43.         ///第一种模式   
  44.         ///</summary>  
  45.         #endregion   
  46.         private const byte REDIRECT_MODE_1 = 0x01;   
  47.   
  48.         //第二种模式  
  49.         #region 第二种模式   
  50.         /**/  
  51.         ///<summary>   
  52.         ///第二种模式   
  53.         ///</summary>  
  54.         #endregion   
  55.         private const byte REDIRECT_MODE_2 = 0x02;   
  56.   
  57.         //每条记录长度  
  58.         #region 每条记录长度   
  59.         /**/  
  60.         ///<summary>   
  61.         ///每条记录长度   
  62.         ///</summary>  
  63.         #endregion   
  64.         private const int IP_RECORD_LENGTH = 7;   
  65.   
  66.         //数据库文件  
  67.         #region 数据库文件   
  68.         /**/  
  69.         ///<summary>   
  70.         ///文件对象   
  71.         ///</summary>  
  72.         #endregion   
  73.         private FileStream ipFile;   
  74.   
  75.         private const string unCountry = "未知国家";   
  76.         private const string unArea = "未知地区";   
  77.   
  78.         //索引开始位置  
  79.         #region 索引开始位置   
  80.         /**/  
  81.         ///<summary>   
  82.         ///索引开始位置   
  83.         ///</summary>  
  84.         #endregion   
  85.         private long ipBegin;   
  86.   
  87.         //索引结束位置  
  88.         #region 索引结束位置   
  89.         /**/  
  90.         ///<summary>   
  91.         ///索引结束位置   
  92.         ///</summary>  
  93.         #endregion   
  94.         private long ipEnd;   
  95.   
  96.         //IP地址对象  
  97.         #region  IP地址对象   
  98.         /**/  
  99.         ///<summary>   
  100.         /// IP对象   
  101.         ///</summary>  
  102.         #endregion   
  103.         private IPLocation loc;   
  104.   
  105.         //存储文本内容  
  106.         #region 存储文本内容   
  107.         /**/  
  108.         ///<summary>   
  109.         ///存储文本内容   
  110.         ///</summary>  
  111.         #endregion   
  112.         private byte[] buf;   
  113.   
  114.         //存储3字节  
  115.         #region 存储3字节   
  116.         /**/  
  117.         ///<summary>   
  118.         ///存储3字节   
  119.         ///</summary>  
  120.         #endregion   
  121.         private byte[] b3;   
  122.   
  123.         //存储4字节  
  124.         #region 存储4字节   
  125.         /**/  
  126.         ///<summary>   
  127.         ///存储4字节IP地址   
  128.         ///</summary>  
  129.         #endregion   
  130.         private byte[] b4;   
  131.   
  132.         //构造函数  
  133.         #region 构造函数   
  134.         /**/  
  135.         ///<summary>   
  136.         ///构造函数   
  137.         ///</summary>   
  138.         ///<param name="ipfile">IP数据库文件绝对路径</param>  
  139.         #endregion   
  140.         public QQWry(string ipfile)   
  141.         {   
  142.   
  143.             buf = new byte[100];   
  144.             b3 = new byte[3];   
  145.             b4 = new byte[4];   
  146.             try  
  147.             {   
  148.                 ipFile = new FileStream(ipfile, FileMode.Open);   
  149.             }   
  150.             catch (Exception ex)   
  151.             {   
  152.                 throw new Exception(ex.Message);   
  153.             }   
  154.             ipBegin = readLong4(0);   
  155.             ipEnd = readLong4(4);   
  156.             loc = new IPLocation();   
  157.         }   
  158.   
  159.         //根据IP地址搜索  
  160.         #region 根据IP地址搜索   
  161.         /**/  
  162.         ///<summary>   
  163.         ///搜索IP地址搜索   
  164.         ///</summary>   
  165.         ///<param name="ip"></param>   
  166.         ///<returns></returns>  
  167.         #endregion   
  168.         public IPLocation SearchIPLocation(string ip)   
  169.         {   
  170.             //将字符IP转换为字节   
  171.             string[] ipSp = ip.Split(‘.’);   
  172.             if (ipSp.Length != 4)   
  173.             {   
  174.                 throw new ArgumentOutOfRangeException("不是合法的IP地址!");   
  175.             }   
  176.             byte[] IP = new byte[4];   
  177.             for (int i = 0; i < IP.Length; i++)   
  178.             {   
  179.                 IP[i] = (byte)(Int32.Parse(ipSp[i]) & 0xFF);   
  180.             }   
  181.   
  182.             IPLocation local = null;   
  183.             long offset = locateIP(IP);   
  184.   
  185.             if (offset != -1)   
  186.             {   
  187.                 local = getIPLocation(offset);   
  188.             }   
  189.   
  190.             if (local == null)   
  191.             {   
  192.                 local = new IPLocation();   
  193.                 local.area = unArea;   
  194.                 local.country = unCountry;   
  195.             }   
  196.             return local;   
  197.         }   
  198.   
  199.         //取得具体信息  
  200.         #region 取得具体信息   
  201.         /**/  
  202.         ///<summary>   
  203.         ///取得具体信息   
  204.         ///</summary>   
  205.         ///<param name="offset"></param>   
  206.         ///<returns></returns>  
  207.         #endregion   
  208.         private IPLocation getIPLocation(long offset)   
  209.         {   
  210.             ipFile.Position = offset + 4;   
  211.             //读取第一个字节判断是否是标志字节   
  212.             byte one = (byte)ipFile.ReadByte();   
  213.             if (one == REDIRECT_MODE_1)   
  214.             {   
  215.                 //第一种模式   
  216.                 //读取国家偏移   
  217.                 long countryOffset = readLong3();   
  218.                 //转至偏移处   
  219.                 ipFile.Position = countryOffset;   
  220.                 //再次检查标志字节   
  221.                 byte b = (byte)ipFile.ReadByte();   
  222.                 if (b == REDIRECT_MODE_2)   
  223.                 {   
  224.                     loc.country = readString(readLong3());   
  225.                     ipFile.Position = countryOffset + 4;   
  226.                 }   
  227.                 else  
  228.                     loc.country = readString(countryOffset);   
  229.   
  230.                 //读取地区标志   
  231.                 loc.area = readArea(ipFile.Position);   
  232.   
  233.             }   
  234.             else if (one == REDIRECT_MODE_2)   
  235.             {   
  236.                 //第二种模式   
  237.                 loc.country = readString(readLong3());   
  238.                 loc.area = readArea(offset + 8);   
  239.             }   
  240.             else  
  241.             {   
  242.                 //普通模式   
  243.                 loc.country = readString(–ipFile.Position);   
  244.                 loc.area = readString(ipFile.Position);   
  245.             }   
  246.             return loc;   
  247.         }   
  248.   
  249.         //取得地区信息  
  250.         #region 取得地区信息   
  251.         /**/  
  252.         ///<summary>   
  253.         ///读取地区名称   
  254.         ///</summary>   
  255.         ///<param name="offset"></param>   
  256.         ///<returns></returns>  
  257.         #endregion   
  258.         private string readArea(long offset)   
  259.         {   
  260.             ipFile.Position = offset;   
  261.             byte one = (byte)ipFile.ReadByte();   
  262.             if (one == REDIRECT_MODE_1 || one == REDIRECT_MODE_2)   
  263.             {   
  264.                 long areaOffset = readLong3(offset + 1);   
  265.                 if (areaOffset == 0)   
  266.                     return unArea;   
  267.                 else  
  268.                 {   
  269.                     return readString(areaOffset);   
  270.                 }   
  271.             }   
  272.             else  
  273.             {   
  274.                 return readString(offset);   
  275.             }   
  276.         }   
  277.   
  278.         //读取字符串  
  279.         #region 读取字符串   
  280.         /**/  
  281.         ///<summary>   
  282.         ///读取字符串   
  283.         ///</summary>   
  284.         ///<param name="offset"></param>   
  285.         ///<returns></returns>  
  286.         #endregion   
  287.         private string readString(long offset)   
  288.         {   
  289.             ipFile.Position = offset;   
  290.             int i = 0;   
  291.             for (i = 0, buf[i] = (byte)ipFile.ReadByte(); buf[i] != (byte)(0); buf[++i] = (byte)ipFile.ReadByte()) ;   
  292.   
  293.             if (i > 0)   
  294.                 return Encoding.Default.GetString(buf, 0, i);   
  295.             else  
  296.                 return "";   
  297.         }   
  298.   
  299.         //查找IP地址所在的绝对偏移量  
  300.         #region 查找IP地址所在的绝对偏移量   
  301.         /**/  
  302.         ///<summary>   
  303.         ///查找IP地址所在的绝对偏移量   
  304.         ///</summary>   
  305.         ///<param name="ip"></param>   
  306.         ///<returns></returns>  
  307.         #endregion   
  308.         private long locateIP(byte[] ip)   
  309.         {   
  310.             long m = 0;   
  311.             int r;   
  312.   
  313.             //比较第一个IP项   
  314.             readIP(ipBegin, b4);   
  315.             r = compareIP(ip, b4);   
  316.             if (r == 0)   
  317.                 return ipBegin;   
  318.             else if (r < 0)   
  319.                 return -1;   
  320.             //开始二分搜索   
  321.             for (long i = ipBegin, j = ipEnd; i < j; )   
  322.             {   
  323.                 m = this.getMiddleOffset(i, j);   
  324.                 readIP(m, b4);   
  325.                 r = compareIP(ip, b4);   
  326.                 if (r > 0)   
  327.                     i = m;   
  328.                 else if (r < 0)   
  329.                 {   
  330.                     if (m == j)   
  331.                     {   
  332.                         j -= IP_RECORD_LENGTH;   
  333.                         m = j;   
  334.                     }   
  335.                     else  
  336.                     {   
  337.                         j = m;   
  338.                     }   
  339.                 }   
  340.                 else  
  341.                     return readLong3(m + 4);   
  342.             }   
  343.             m = readLong3(m + 4);   
  344.             readIP(m, b4);   
  345.             r = compareIP(ip, b4);   
  346.             if (r <= 0)   
  347.                 return m;   
  348.             else  
  349.                 return -1;   
  350.         }   
  351.   
  352.         //读出4字节的IP地址  
  353.         #region 读出4字节的IP地址   
  354.         /**/  
  355.         ///<summary>   
  356.         ///从当前位置读取四字节,此四字节是IP地址   
  357.         ///</summary>   
  358.         ///<param name="offset"></param>   
  359.         ///<param name="ip"></param>  
  360.         #endregion   
  361.         private void readIP(long offset, byte[] ip)   
  362.         {   
  363.             ipFile.Position = offset;   
  364.             ipFile.Read(ip, 0, ip.Length);   
  365.             byte tmp = ip[0];   
  366.             ip[0] = ip[3];   
  367.             ip[3] = tmp;   
  368.             tmp = ip[1];   
  369.             ip[1] = ip[2];   
  370.             ip[2] = tmp;   
  371.         }   
  372.   
  373.         //比较IP地址是否相同  
  374.         #region 比较IP地址是否相同   
  375.         /**/  
  376.         ///<summary>   
  377.         ///比较IP地址是否相同   
  378.         ///</summary>   
  379.         ///<param name="ip"></param>   
  380.         ///<param name="beginIP"></param>   
  381.         ///<returns>0:相等,1:ip大于beginIP,-1:小于</returns>  
  382.         #endregion   
  383.         private int compareIP(byte[] ip, byte[] beginIP)   
  384.         {   
  385.             for (int i = 0; i < 4; i++)   
  386.             {   
  387.                 int r = compareByte(ip[i], beginIP[i]);   
  388.                 if (r != 0)   
  389.                     return r;   
  390.             }   
  391.             return 0;   
  392.         }   
  393.   
  394.         //比较两个字节是否相等  
  395.         #region 比较两个字节是否相等   
  396.         /**/  
  397.         ///<summary>   
  398.         ///比较两个字节是否相等   
  399.         ///</summary>   
  400.         ///<param name="bsrc"></param>   
  401.         ///<param name="bdst"></param>   
  402.         ///<returns></returns>  
  403.         #endregion   
  404.         private int compareByte(byte bsrc, byte bdst)   
  405.         {   
  406.             if ((bsrc & 0xFF) > (bdst & 0xFF))   
  407.                 return 1;   
  408.             else if ((bsrc ^ bdst) == 0)   
  409.                 return 0;   
  410.             else  
  411.                 return -1;   
  412.         }   
  413.   
  414.         //根据当前位置读取4字节  
  415.         #region 根据当前位置读取4字节   
  416.         /**/  
  417.         ///<summary>   
  418.         ///从当前位置读取4字节,转换为长整型   
  419.         ///</summary>   
  420.         ///<param name="offset"></param>   
  421.         ///<returns></returns>  
  422.         #endregion   
  423.         private long readLong4(long offset)   
  424.         {   
  425.             long ret = 0;   
  426.             ipFile.Position = offset;   
  427.             ret |= (ipFile.ReadByte() & 0xFF);   
  428.             ret |= ((ipFile.ReadByte() << 8) & 0xFF00);   
  429.             ret |= ((ipFile.ReadByte() << 16) & 0xFF0000);   
  430.             ret |= ((ipFile.ReadByte() << 24) & 0xFF000000);   
  431.             return ret;   
  432.         }   
  433.   
  434.         //根据当前位置,读取3字节  
  435.         #region 根据当前位置,读取3字节   
  436.         /**/  
  437.         ///<summary>   
  438.         ///根据当前位置,读取3字节   
  439.         ///</summary>   
  440.         ///<param name="offset"></param>   
  441.         ///<returns></returns>  
  442.         #endregion   
  443.         private long readLong3(long offset)   
  444.         {   
  445.             long ret = 0;   
  446.             ipFile.Position = offset;   
  447.             ret |= (ipFile.ReadByte() & 0xFF);   
  448.             ret |= ((ipFile.ReadByte() << 8) & 0xFF00);   
  449.             ret |= ((ipFile.ReadByte() << 16) & 0xFF0000);   
  450.             return ret;   
  451.         }   
  452.   
  453.         //从当前位置读取3字节  
  454.         #region 从当前位置读取3字节   
  455.         /**/  
  456.         ///<summary>   
  457.         ///从当前位置读取3字节   
  458.         ///</summary>   
  459.         ///<returns></returns>  
  460.         #endregion   
  461.         private long readLong3()   
  462.         {   
  463.             long ret = 0;   
  464.             ret |= (ipFile.ReadByte() & 0xFF);   
  465.             ret |= ((ipFile.ReadByte() << 8) & 0xFF00);   
  466.             ret |= ((ipFile.ReadByte() << 16) & 0xFF0000);   
  467.             return ret;   
  468.         }   
  469.   
  470.         //取得begin和end之间的偏移量  
  471.         #region 取得begin和end之间的偏移量   
  472.         /**/  
  473.         ///<summary>   
  474.         ///取得begin和end中间的偏移   
  475.         ///</summary>   
  476.         ///<param name="begin"></param>   
  477.         ///<param name="end"></param>   
  478.         ///<returns></returns>  
  479.         #endregion   
  480.         private long getMiddleOffset(long begin, long end)   
  481.         {   
  482.             long records = (end – begin) / IP_RECORD_LENGTH;   
  483.             records >>= 1;   
  484.             if (records == 0)   
  485.                 records = 1;   
  486.             return begin + records * IP_RECORD_LENGTH;   
  487.         }   
  488.     } //class QQWry   
  489.   
  490.     public class IPLocation   
  491.     {   
  492.         public String country;   
  493.         public String area;   
  494.   
  495.         public IPLocation()   
  496.         {   
  497.             country = area = "";   
  498.         }   
  499.   
  500.         public IPLocation getCopy()   
  501.         {   
  502.             IPLocation ret = new IPLocation();   
  503.             ret.country = country;   
  504.             ret.area = area;   
  505.             return ret;   
  506.         }   
  507.     }   
  508. }   

 

文章来源:http://www.svnhost.cn/Article/Detail-30.shtml

本站原创文章,请勿复制转载
版权声明:除特别注明外,本站所有文章均为原创,未经许可请勿复制、转载
2008-06-01
4,420 views
标签: , ,
  1. 不高亮的代码,看得头大一圈了。 :)

  2. @leo,呵呵,这些是以前从sablog导过来的
    后来转到wp后没去整理

发表评论

注意: 评论者允许使用'@user空格'的方式将自己的评论通知另外评论者。例如, ABC是本文的评论者之一,则使用'@ABC '(不包括单引号)将会自动将您的评论发送给ABC。使用'@all ',将会将评论发送给之前所有其它评论者。请务必注意user必须和评论者名相匹配(大小写一致)。