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

来源:互联网 发布:java解决高并发 编辑:程序博客网 时间:2024/05/17 00:18
http://blog.csdn.net/fwj380891124/article/details/7682619
 
QQWry数据库下载地址:<a href="http://download.csdn.net/detail/fwj380891124/4385554">http://download.csdn.net/detail/fwj380891124/4385554</a> 
[csharp] view plaincopyprint?
  1. using System; 
  2.  
  3. using System.Collections.Generic; 
  4.  
  5. using System.Text; 
  6.  
  7. using System.IO; 
  8.  
  9. using System.Web; 
  10.  
  11. using System.Configuration; 
  12.  
  13.  
  14.  
  15. namespace BLL 
  16.  
  17.  
  18.     public class IPLocationSearch 
  19.  
  20.     { 
  21.  
  22.         private staticreadonly QQWry qq =new QQWry(ConfigurationManager.AppSettings["ip"] +"qqwry.dat"); 
  23.  
  24.  
  25.  
  26.         public static IPLocation GetIPLocation(string ip) 
  27.  
  28.         { 
  29.  
  30.             return qq.SearchIPLocation(ip); 
  31.  
  32.         } 
  33.  
  34.     } 
  35.  
  36.  
  37.  
  38.     /*
  39.     使用方法:
  40.     例子:
  41. BDQQ.Data.QQWry qq=new BDQQ.Data.QQWry("d:\\QQWry.Dat");
  42.     BDQQ.Data.IPLocation ip=qq.SearchIPLocation("127.0.0.1");//这里添写IP地址
  43.     Console.WriteLine(ip.country);//国家
  44.     Console.WriteLine(ip.area);//地区
  45.     */ 
  46.  
  47.  
  48.  
  49.     //以下是类文件 
  50.  
  51.     //根据LumaQQ改写而成. 
  52.  
  53.  
  54.  
  55.     /**/ 
  56.  
  57.     ///<summary> 
  58.  
  59.     /// QQWry 的摘要说明。 
  60.  
  61.     ///</summary> 
  62.  
  63.     public class QQWry 
  64.  
  65.     { 
  66.  
  67.         //第一种模式 
  68.         #region 第一种模式 
  69.  
  70.         /**/ 
  71.  
  72.         ///<summary> 
  73.  
  74.         ///第一种模式 
  75.  
  76.         ///</summary> 
  77.         #endregion 
  78.  
  79.         private constbyte REDIRECT_MODE_1 = 0x01; 
  80.  
  81.  
  82.  
  83.         //第二种模式 
  84.         #region 第二种模式 
  85.  
  86.         /**/ 
  87.  
  88.         ///<summary> 
  89.  
  90.         ///第二种模式 
  91.  
  92.         ///</summary> 
  93.         #endregion 
  94.  
  95.         private constbyte REDIRECT_MODE_2 = 0x02; 
  96.  
  97.  
  98.  
  99.         //每条记录长度 
  100.         #region 每条记录长度 
  101.  
  102.         /**/ 
  103.  
  104.         ///<summary> 
  105.  
  106.         ///每条记录长度 
  107.  
  108.         ///</summary> 
  109.         #endregion 
  110.  
  111.         private constint IP_RECORD_LENGTH = 7; 
  112.  
  113.  
  114.  
  115.         //数据库文件 
  116.         #region 数据库文件 
  117.  
  118.         /**/ 
  119.  
  120.         ///<summary> 
  121.  
  122.         ///文件对象 
  123.  
  124.         ///</summary> 
  125.         #endregion 
  126.  
  127.         private FileStream ipFile; 
  128.  
  129.  
  130.  
  131.         private conststring unCountry ="未知国家"
  132.  
  133.         private conststring unArea ="未知地区"
  134.  
  135.  
  136.  
  137.         //索引开始位置 
  138.         #region 索引开始位置 
  139.  
  140.         /**/ 
  141.  
  142.         ///<summary> 
  143.  
  144.         ///索引开始位置 
  145.  
  146.         ///</summary> 
  147.         #endregion 
  148.  
  149.         private long ipBegin; 
  150.  
  151.  
  152.  
  153.         //索引结束位置 
  154.         #region 索引结束位置 
  155.  
  156.         /**/ 
  157.  
  158.         ///<summary> 
  159.  
  160.         ///索引结束位置 
  161.  
  162.         ///</summary> 
  163.         #endregion 
  164.  
  165.         private long ipEnd; 
  166.  
  167.  
  168.  
  169.         //IP地址对象 
  170.         #region  IP地址对象 
  171.  
  172.         /**/ 
  173.  
  174.         ///<summary> 
  175.  
  176.         /// IP对象 
  177.  
  178.         ///</summary> 
  179.         #endregion 
  180.  
  181.         private IPLocation loc; 
  182.  
  183.  
  184.  
  185.         //存储文本内容 
  186.         #region 存储文本内容 
  187.  
  188.         /**/ 
  189.  
  190.         ///<summary> 
  191.  
  192.         ///存储文本内容 
  193.  
  194.         ///</summary> 
  195.         #endregion 
  196.  
  197.         private byte[] buf; 
  198.  
  199.  
  200.  
  201.         //存储3字节 
  202.         #region 存储3字节 
  203.  
  204.         /**/ 
  205.  
  206.         ///<summary> 
  207.  
  208.         ///存储3字节 
  209.  
  210.         ///</summary> 
  211.         #endregion 
  212.  
  213.         private byte[] b3; 
  214.  
  215.  
  216.  
  217.         //存储4字节 
  218.         #region 存储4字节 
  219.  
  220.         /**/ 
  221.  
  222.         ///<summary> 
  223.  
  224.         ///存储4字节IP地址 
  225.  
  226.         ///</summary> 
  227.         #endregion 
  228.  
  229.         private byte[] b4; 
  230.  
  231.  
  232.  
  233.         //构造函数 
  234.         #region 构造函数 
  235.  
  236.         /**/ 
  237.  
  238.         ///<summary> 
  239.  
  240.         ///构造函数 
  241.  
  242.         ///</summary> 
  243.  
  244.         ///<param name="ipfile">IP数据库文件绝对路径</param> 
  245.         #endregion 
  246.  
  247.         public QQWry(string ipfile) 
  248.  
  249.         { 
  250.  
  251.  
  252.  
  253.             buf = new byte[100]; 
  254.  
  255.             b3 = new byte[3]; 
  256.  
  257.             b4 = new byte[4]; 
  258.  
  259.             try 
  260.  
  261.             { 
  262.  
  263.                 ipFile = new FileStream(ipfile, FileMode.Open); 
  264.  
  265.             } 
  266.  
  267.             catch (Exception ex) 
  268.  
  269.             { 
  270.  
  271.                 throw new Exception(ex.Message); 
  272.  
  273.             } 
  274.  
  275.             ipBegin = readLong4(0); 
  276.  
  277.             ipEnd = readLong4(4); 
  278.  
  279.             loc = new IPLocation(); 
  280.  
  281.         } 
  282.  
  283.  
  284.  
  285.         //根据IP地址搜索 
  286.         #region 根据IP地址搜索 
  287.  
  288.         /**/ 
  289.  
  290.         ///<summary> 
  291.  
  292.         ///搜索IP地址搜索 
  293.  
  294.         ///</summary> 
  295.  
  296.         ///<param name="ip"></param> 
  297.  
  298.         ///<returns></returns> 
  299.         #endregion 
  300.  
  301.         public IPLocation SearchIPLocation(string ip) 
  302.  
  303.         { 
  304.  
  305.             //将字符IP转换为字节 
  306.  
  307.             string[] ipSp = ip.Split('.'); 
  308.  
  309.             if (ipSp.Length != 4) 
  310.  
  311.             { 
  312.  
  313.                 throw new ArgumentOutOfRangeException("不是合法的IP地址!"); 
  314.  
  315.             } 
  316.  
  317.             byte[] IP = new byte[4]; 
  318.  
  319.             for (int i = 0; i < IP.Length; i++) 
  320.  
  321.             { 
  322.  
  323.                 IP[i] = (byte)(Int32.Parse(ipSp[i]) & 0xFF); 
  324.  
  325.             } 
  326.  
  327.  
  328.  
  329.             IPLocation local = null
  330.  
  331.             long offset = locateIP(IP); 
  332.  
  333.  
  334.  
  335.             if (offset != -1) 
  336.  
  337.             { 
  338.  
  339.                 local = getIPLocation(offset); 
  340.  
  341.             } 
  342.  
  343.  
  344.  
  345.             if (local ==null
  346.  
  347.             { 
  348.  
  349.                 local = new IPLocation(); 
  350.  
  351.                 local.area = unArea; 
  352.  
  353.                 local.country = unCountry; 
  354.  
  355.             } 
  356.  
  357.             return local; 
  358.  
  359.         } 
  360.  
  361.  
  362.  
  363.         //取得具体信息 
  364.         #region 取得具体信息 
  365.  
  366.         /**/ 
  367.  
  368.         ///<summary> 
  369.  
  370.         ///取得具体信息 
  371.  
  372.         ///</summary> 
  373.  
  374.         ///<param name="offset"></param> 
  375.  
  376.         ///<returns></returns> 
  377.         #endregion 
  378.  
  379.         private IPLocation getIPLocation(long offset) 
  380.  
  381.         { 
  382.  
  383.             ipFile.Position = offset + 4; 
  384.  
  385.             //读取第一个字节判断是否是标志字节 
  386.  
  387.             byte one = (byte)ipFile.ReadByte(); 
  388.  
  389.             if (one == REDIRECT_MODE_1) 
  390.  
  391.             { 
  392.  
  393.                 //第一种模式 
  394.  
  395.                 //读取国家偏移 
  396.  
  397.                 long countryOffset = readLong3(); 
  398.  
  399.                 //转至偏移处 
  400.  
  401.                 ipFile.Position = countryOffset; 
  402.  
  403.                 //再次检查标志字节 
  404.  
  405.                 byte b = (byte)ipFile.ReadByte(); 
  406.  
  407.                 if (b == REDIRECT_MODE_2) 
  408.  
  409.                 { 
  410.  
  411.                     loc.country = readString(readLong3()); 
  412.  
  413.                     ipFile.Position = countryOffset + 4; 
  414.  
  415.                 } 
  416.  
  417.                 else 
  418.  
  419.                     loc.country = readString(countryOffset); 
  420.  
  421.  
  422.  
  423.                 //读取地区标志 
  424.  
  425.                 loc.area = readArea(ipFile.Position); 
  426.  
  427.  
  428.  
  429.             } 
  430.  
  431.             else if (one == REDIRECT_MODE_2) 
  432.  
  433.             { 
  434.  
  435.                 //第二种模式 
  436.  
  437.                 loc.country = readString(readLong3()); 
  438.  
  439.                 loc.area = readArea(offset + 8); 
  440.  
  441.             } 
  442.  
  443.             else 
  444.  
  445.             { 
  446.  
  447.                 //普通模式 
  448.  
  449.                 loc.country = readString(--ipFile.Position); 
  450.  
  451.                 loc.area = readString(ipFile.Position); 
  452.  
  453.             } 
  454.  
  455.             return loc; 
  456.  
  457.         } 
  458.  
  459.  
  460.  
  461.         //取得地区信息 
  462.         #region 取得地区信息 
  463.  
  464.         /**/ 
  465.  
  466.         ///<summary> 
  467.  
  468.         ///读取地区名称 
  469.  
  470.         ///</summary> 
  471.  
  472.         ///<param name="offset"></param> 
  473.  
  474.         ///<returns></returns> 
  475.         #endregion 
  476.  
  477.         private string readArea(long offset) 
  478.  
  479.         { 
  480.  
  481.             ipFile.Position = offset; 
  482.  
  483.             byte one = (byte)ipFile.ReadByte(); 
  484.  
  485.             if (one == REDIRECT_MODE_1 || one == REDIRECT_MODE_2) 
  486.  
  487.             { 
  488.  
  489.                 long areaOffset = readLong3(offset + 1); 
  490.  
  491.                 if (areaOffset == 0) 
  492.  
  493.                     return unArea; 
  494.  
  495.                 else 
  496.  
  497.                 { 
  498.  
  499.                     return readString(areaOffset); 
  500.  
  501.                 } 
  502.  
  503.             } 
  504.  
  505.             else 
  506.  
  507.             { 
  508.  
  509.                 return readString(offset); 
  510.  
  511.             } 
  512.  
  513.         } 
  514.  
  515.  
  516.  
  517.         //读取字符串 
  518.         #region 读取字符串 
  519.  
  520.         /**/ 
  521.  
  522.         ///<summary> 
  523.  
  524.         ///读取字符串 
  525.  
  526.         ///</summary> 
  527.  
  528.         ///<param name="offset"></param> 
  529.  
  530.         ///<returns></returns> 
  531.         #endregion 
  532.  
  533.         private string readString(long offset) 
  534.  
  535.         { 
  536.  
  537.             ipFile.Position = offset; 
  538.  
  539.             int i = 0; 
  540.  
  541.             for (i = 0, buf[i] = (byte)ipFile.ReadByte(); buf[i] != (byte)(0); buf[++i] = (byte)ipFile.ReadByte()) ; 
  542.  
  543.  
  544.  
  545.             if (i > 0) 
  546.  
  547.                 return Encoding.Default.GetString(buf, 0, i); 
  548.  
  549.             else 
  550.  
  551.                 return ""
  552.  
  553.         } 
  554.  
  555.  
  556.  
  557.         //查找IP地址所在的绝对偏移量 
  558.         #region 查找IP地址所在的绝对偏移量 
  559.  
  560.         /**/ 
  561.  
  562.         ///<summary> 
  563.  
  564.         ///查找IP地址所在的绝对偏移量 
  565.  
  566.         ///</summary> 
  567.  
  568.         ///<param name="ip"></param> 
  569.  
  570.         ///<returns></returns> 
  571.         #endregion 
  572.  
  573.         private long locateIP(byte[] ip) 
  574.  
  575.         { 
  576.  
  577.             long m = 0; 
  578.  
  579.             int r; 
  580.  
  581.  
  582.  
  583.             //比较第一个IP项 
  584.  
  585.             readIP(ipBegin, b4); 
  586.  
  587.             r = compareIP(ip, b4); 
  588.  
  589.             if (r == 0) 
  590.  
  591.                 return ipBegin; 
  592.  
  593.             else if (r < 0) 
  594.  
  595.                 return -1; 
  596.  
  597.             //开始二分搜索 
  598.  
  599.             for (long i = ipBegin, j = ipEnd; i < j; ) 
  600.  
  601.             { 
  602.  
  603.                 m = this.getMiddleOffset(i, j); 
  604.  
  605.                 readIP(m, b4); 
  606.  
  607.                 r = compareIP(ip, b4); 
  608.  
  609.                 if (r > 0) 
  610.  
  611.                     i = m; 
  612.  
  613.                 else if (r < 0) 
  614.  
  615.                 { 
  616.  
  617.                     if (m == j) 
  618.  
  619.                     { 
  620.  
  621.                         j -= IP_RECORD_LENGTH; 
  622.  
  623.                         m = j; 
  624.  
  625.                     } 
  626.  
  627.                     else 
  628.  
  629.                     { 
  630.  
  631.                         j = m; 
  632.  
  633.                     } 
  634.  
  635.                 } 
  636.  
  637.                 else 
  638.  
  639.                     return readLong3(m + 4); 
  640.  
  641.             } 
  642.  
  643.             m = readLong3(m + 4); 
  644.  
  645.             readIP(m, b4); 
  646.  
  647.             r = compareIP(ip, b4); 
  648.  
  649.             if (r <= 0) 
  650.  
  651.                 return m; 
  652.  
  653.             else 
  654.  
  655.                 return -1; 
  656.  
  657.         } 
  658.  
  659.  
  660.  
  661.         //读出4字节的IP地址 
  662.         #region 读出4字节的IP地址 
  663.  
  664.         /**/ 
  665.  
  666.         ///<summary> 
  667.  
  668.         ///从当前位置读取四字节,此四字节是IP地址 
  669.  
  670.         ///</summary> 
  671.  
  672.         ///<param name="offset"></param> 
  673.  
  674.         ///<param name="ip"></param> 
  675.         #endregion 
  676.  
  677.         private void readIP(long offset,byte[] ip) 
  678.  
  679.         { 
  680.  
  681.             ipFile.Position = offset; 
  682.  
  683.             ipFile.Read(ip, 0, ip.Length); 
  684.  
  685.             byte tmp = ip[0]; 
  686.  
  687.             ip[0] = ip[3]; 
  688.  
  689.             ip[3] = tmp; 
  690.  
  691.             tmp = ip[1]; 
  692.  
  693.             ip[1] = ip[2]; 
  694.  
  695.             ip[2] = tmp; 
  696.  
  697.         } 
  698.  
  699.  
  700.  
  701.         //比较IP地址是否相同 
  702.         #region 比较IP地址是否相同 
  703.  
  704.         /**/ 
  705.  
  706.         ///<summary> 
  707.  
  708.         ///比较IP地址是否相同 
  709.  
  710.         ///</summary> 
  711.  
  712.         ///<param name="ip"></param> 
  713.  
  714.         ///<param name="beginIP"></param> 
  715.  
  716.         ///<returns>0:相等,1:ip大于beginIP,-1:小于</returns> 
  717.         #endregion 
  718.  
  719.         private int compareIP(byte[] ip,byte[] beginIP) 
  720.  
  721.         { 
  722.  
  723.             for (int i = 0; i < 4; i++) 
  724.  
  725.             { 
  726.  
  727.                 int r = compareByte(ip[i], beginIP[i]); 
  728.  
  729.                 if (r != 0) 
  730.  
  731.                     return r; 
  732.  
  733.             } 
  734.  
  735.             return 0; 
  736.  
  737.         } 
  738.  
  739.  
  740.  
  741.         //比较两个字节是否相等 
  742.         #region 比较两个字节是否相等 
  743.  
  744.         /**/ 
  745.  
  746.         ///<summary> 
  747.  
  748.         ///比较两个字节是否相等 
  749.  
  750.         ///</summary> 
  751.  
  752.         ///<param name="bsrc"></param> 
  753.  
  754.         ///<param name="bdst"></param> 
  755.  
  756.         ///<returns></returns> 
  757.         #endregion 
  758.  
  759.         private int compareByte(byte bsrc,byte bdst) 
  760.  
  761.         { 
  762.  
  763.             if ((bsrc & 0xFF) > (bdst & 0xFF)) 
  764.  
  765.                 return 1; 
  766.  
  767.             else if ((bsrc ^ bdst) == 0) 
  768.  
  769.                 return 0; 
  770.  
  771.             else 
  772.  
  773.                 return -1; 
  774.  
  775.         } 
  776.  
  777.  
  778.  
  779.         //根据当前位置读取4字节 
  780.         #region 根据当前位置读取4字节 
  781.  
  782.         /**/ 
  783.  
  784.         ///<summary> 
  785.  
  786.         ///从当前位置读取4字节,转换为长整型 
  787.  
  788.         ///</summary> 
  789.  
  790.         ///<param name="offset"></param> 
  791.  
  792.         ///<returns></returns> 
  793.         #endregion 
  794.  
  795.         private long readLong4(long offset) 
  796.  
  797.         { 
  798.  
  799.             long ret = 0; 
  800.  
  801.             ipFile.Position = offset; 
  802.  
  803.             ret |= (ipFile.ReadByte() & 0xFF); 
  804.  
  805.             ret |= ((ipFile.ReadByte() << 8) & 0xFF00); 
  806.  
  807.             ret |= ((ipFile.ReadByte() << 16) & 0xFF0000); 
  808.  
  809.             ret |= ((ipFile.ReadByte() << 24) & 0xFF000000); 
  810.  
  811.             return ret; 
  812.  
  813.         } 
  814.  
  815.  
  816.  
  817.         //根据当前位置,读取3字节 
  818.         #region 根据当前位置,读取3字节 
  819.  
  820.         /**/ 
  821.  
  822.         ///<summary> 
  823.  
  824.         ///根据当前位置,读取3字节 
  825.  
  826.         ///</summary> 
  827.  
  828.         ///<param name="offset"></param> 
  829.  
  830.         ///<returns></returns> 
  831.         #endregion 
  832.  
  833.         private long readLong3(long offset) 
  834.  
  835.         { 
  836.  
  837.             long ret = 0; 
  838.  
  839.             ipFile.Position = offset; 
  840.  
  841.             ret |= (ipFile.ReadByte() & 0xFF); 
  842.  
  843.             ret |= ((ipFile.ReadByte() << 8) & 0xFF00); 
  844.  
  845.             ret |= ((ipFile.ReadByte() << 16) & 0xFF0000); 
  846.  
  847.             return ret; 
  848.  
  849.         } 
  850.  
  851.  
  852.  
  853.         //从当前位置读取3字节 
  854.         #region 从当前位置读取3字节 
  855.  
  856.         /**/ 
  857.  
  858.         ///<summary> 
  859.  
  860.         ///从当前位置读取3字节 
  861.  
  862.         ///</summary> 
  863.  
  864.         ///<returns></returns> 
  865.         #endregion 
  866.  
  867.         private long readLong3() 
  868.  
  869.         { 
  870.  
  871.             long ret = 0; 
  872.  
  873.             ret |= (ipFile.ReadByte() & 0xFF); 
  874.  
  875.             ret |= ((ipFile.ReadByte() << 8) & 0xFF00); 
  876.  
  877.             ret |= ((ipFile.ReadByte() << 16) & 0xFF0000); 
  878.  
  879.             return ret; 
  880.  
  881.         } 
  882.  
  883.  
  884.  
  885.         //取得begin和end之间的偏移量 
  886.         #region 取得begin和end之间的偏移量 
  887.  
  888.         /**/ 
  889.  
  890.         ///<summary> 
  891.  
  892.         ///取得begin和end中间的偏移 
  893.  
  894.         ///</summary> 
  895.  
  896.         ///<param name="begin"></param> 
  897.  
  898.         ///<param name="end"></param> 
  899.  
  900.         ///<returns></returns> 
  901.         #endregion 
  902.  
  903.         private long getMiddleOffset(long begin,long end) 
  904.  
  905.         { 
  906.  
  907.             long records = (end - begin) / IP_RECORD_LENGTH; 
  908.  
  909.             records >>= 1; 
  910.  
  911.             if (records == 0) 
  912.  
  913.                 records = 1; 
  914.  
  915.             return begin + records * IP_RECORD_LENGTH; 
  916.  
  917.         } 
  918.  
  919.     } //class QQWry 
  920.  
  921.  
  922.  
  923.     public class IPLocation 
  924.  
  925.     { 
  926.  
  927.         public String country; 
  928.  
  929.         public String area; 
  930.  
  931.  
  932.  
  933.         public IPLocation() 
  934.  
  935.         { 
  936.  
  937.             country = area = ""
  938.  
  939.         } 
  940.  
  941.  
  942.  
  943.         public IPLocation getCopy() 
  944.  
  945.         { 
  946.  
  947.             IPLocation ret = new IPLocation(); 
  948.  
  949.             ret.country = country; 
  950.  
  951.             ret.area = area; 
  952.  
  953.             return ret; 
  954.  
  955.         } 
  956.  
  957.     } 
  958.  
  959. }
原创粉丝点击