[C#]纯真IP数据库解析器
2011-05-16 15:04
786 查看
这个星期六日研究了下“纯真IP数据库”的格式,并且自己用C#写了个解析器,参考了LumaQQ作者的文章《纯真IP数据库格式详解》:http://lumaqq.linuxsir.org/article/qqwry_format_detail.html
和二分搜索法的C++描述http://baike.baidu.com/view/1881881.htm
数据库的格式在LumaQQ的文章中已有详细描述,下面放上主要的代码:
代码在VS2010+Windows 7下测试成功。
完整的代码在这里下载:
/Uploads/Images/Content/202010/10/de2c3679d7baf547b54c0e776654a177.gif
和二分搜索法的C++描述http://baike.baidu.com/view/1881881.htm
数据库的格式在LumaQQ的文章中已有详细描述,下面放上主要的代码:
//选择数据库文件并显示数据库的版本等信息 private void btnBrowse_Click(object sender, EventArgs e) { if (ofdQQWry.ShowDialog() != DialogResult.Cancel) { txtQQWry.Text = ofdQQWry.FileName; } tvwWryInfo.Nodes.Clear(); tvwWryInfo.Nodes.Add("VER", "纯真数据库版本"); tvwWryInfo.Nodes.Add("FI", "第一条索引的绝对偏移"); tvwWryInfo.Nodes.Add("LI", "最后一条索引的绝对偏移"); tvwWryInfo.Nodes.Add("IPCNT", "可查询的 IP 段数量"); try { //读取数据库内容 FileStream fsQQWry = new FileStream(txtQQWry.Text, FileMode.Open); if (m_abQQWry != null) m_abQQWry = null; m_abQQWry = new byte[fsQQWry.Length]; fsQQWry.Read(m_abQQWry, 0, (int)fsQQWry.Length); fsQQWry.Close(); //获取文件头(索引绝对偏移(8 字节) = 第一条索引偏移(4 字节) + 第二条索引偏移(4 字节)) iFI = BitConverter.ToInt32(m_abQQWry, 0); iLI = BitConverter.ToInt32(m_abQQWry, 4); tvwWryInfo.Nodes["FI"].Nodes.Add(iFI.ToString("#,#")); tvwWryInfo.Nodes["LI"].Nodes.Add(iLI.ToString("#,#")); //可查询的 IP 段数量(每条索引(7 字节) = IP(4 字节) + 绝对偏移(3 字节)) tvwWryInfo.Nodes["IPCNT"].Nodes.Add(((iLI - iFI) / 7 + 1).ToString("#,# 个")); //获取版本(其实就是最后一条索引指向的地址信息,IP 地址为 255.255.255.0) int pVer = 0; byte[] abVer = new byte[4]; Array.Copy(m_abQQWry, iLI + 4, abVer, 0, 3); pVer = BitConverter.ToInt32(abVer, 0); string sVer = GetAddress(pVer, (m_abQQWry[pVer + 4] > 0x02), true); tvwWryInfo.Nodes["VER"].Nodes.Add(sVer.Split("/t".ToCharArray())[1]); tvwWryInfo.Nodes["VER"].Nodes.Add(sVer.Split("/t".ToCharArray())[2]); //记录所有可查询 IP 条目,稍后用来搜索使用 m_aiIP = new int[(iLI - iFI) / 7 + 1]; for (int i = iFI; i < iLI + 7; i += 7) { m_aiIP[(i - iFI) / 7] = BitConverter.ToInt32(m_abQQWry, i); } btnDecompress.Enabled = true; btnQuery.Enabled = true; } catch (Exception ex) { MessageBox.Show(ex.ToString()); } }
/// <summary> /// 获取指定偏移对应的 IP 信息 /// </summary> /// <param name="iOffset">绝对偏移地址</param> /// <param name="bSimple">是否简单的记录方式(即国家和地区都没有使用重定向)</param> /// <param name="bGetIP">是否获取 IP</param> /// <returns>用 '/0' 分割的国家名和地区名</returns> private string GetAddress(int iOffset, bool bSimple, bool bGetIP) { int i = 0; string sRst = ""; byte[] abOffset = new byte[4]; if (bGetIP) { byte[] abIP = new byte[4]; i = IPAddress.HostToNetworkOrder(BitConverter.ToInt32(m_abQQWry, iOffset)); abIP = BitConverter.GetBytes(i); sRst = new IPAddress(abIP).ToString() + '/t'; iOffset += 4; } switch (m_abQQWry[iOffset]) { case 0x01: //重定向模式 1(国家名和地区名均在同一偏移处) Array.Copy(m_abQQWry, iOffset + 1, abOffset, 0, 3); i = BitConverter.ToInt32(abOffset, 0); if (i == 0) { sRst += "未知国家/t未知地区/t"; } else { string sTmp = GetAddress(i, false, false); sRst += sTmp; sRst += GetAddress(i + ((m_abQQWry[i] > 0x02) ? Encoding.Default.GetByteCount(sTmp) : 4), false, false); } break; case 0x02: //重定向模式 2(国家名为偏移值,地区名为字符串) Array.Copy(m_abQQWry, iOffset + 1, abOffset, 0, 3); i = BitConverter.ToInt32(abOffset, 0); //获取国家 if (i == 0) { sRst += "未知国家/t"; } else { sRst += GetAddress(i, false, false); } //获取地区 if (bGetIP) sRst += GetAddress(iOffset + 4, false, false); break; default: //直接字符串 i = iOffset; byte bStr = 0; List<byte> lstStr = new List<byte>(); do { bStr = m_abQQWry[i++]; if (bStr == 0) break; lstStr.Add(bStr); } while (true); sRst += Encoding.Default.GetString(lstStr.ToArray()) + '/t'; //继续读取地区名 if (bGetIP) { sRst += GetAddress(i, false, false); } break; } return sRst; }
//查询指定 IP/域名的信息 private void btnQuery_Click(object sender, EventArgs e) { IPAddress IPQuery = Dns.GetHostAddresses(txtIP.Text)[0]; if (IPQuery == null) { MessageBox.Show("请填入正确的 IP 地址或域名!"); return; } lstIPInfo.Items.Clear(); int iOffset = 0; DateTime nt = DateTime.Now; byte[] abOffset = new byte[4]; uint uiIP = BitConverter.ToUInt32(IPQuery.GetAddressBytes(), 0); uiIP = (uint)IPAddress.NetworkToHostOrder((int)uiIP); //二分法查找 IP 所在段 int j, l, r; j = 0; l = 0; r = m_aiIP.Length - 1; iOffset = (l + r) / 2; while (l <= r) { if ((uint)m_aiIP[iOffset] < uiIP) l = iOffset + 1; else r = iOffset - 1; iOffset = (l + r) / 2; if ((uint)m_aiIP[iOffset] == uiIP) break; j++; } string sIP = new IPAddress(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(m_aiIP[iOffset]))).ToString(); Array.Copy(m_abQQWry, iFI + iOffset * 7 + 4, abOffset, 0, 3); iOffset = BitConverter.ToInt32(abOffset, 0); string sRst = GetAddress(iOffset, (m_abQQWry[iOffset + 4] > 0x02), true); try { lstIPInfo.Items.Add("您查询的计算机名为:" + Dns.GetHostEntry(IPQuery).HostName); } catch (Exception) { lstIPInfo.Items.Add("您查询的计算机名无法解析!"); } lstIPInfo.Items.Add("对应的 IP 为:" + IPQuery.ToString()); lstIPInfo.Items.Add("数据库中匹配的 IP 段为:" + sIP + " - " + sRst.Split('/t')[0]); lstIPInfo.Items.Add("您查询的信息如下:"); lstIPInfo.Items.Add(""); lstIPInfo.Items.Add(sRst.Split('/t')[1]); lstIPInfo.Items.Add(sRst.Split('/t')[2]); lstIPInfo.Items.Add(""); lstIPInfo.Items.Add("索引查询次数:" + j.ToString() + " 次"); lstIPInfo.Items.Add("信息查询耗时:" + ((DateTime.Now.Ticks - nt.Ticks) / 1000).ToString("#,#0") + " 毫秒"); }
//将数据库解压为txt格式的文件 private void btnDecompress_Click(object sender, EventArgs e) { if ((txtQQWry.Text.Length == 0) | (!File.Exists(txtQQWry.Text))) { MessageBox.Show("请先选择一个正确的纯真数据库路径!"); return; } try { if (sfdDecompress.ShowDialog() == DialogResult.Cancel) return; FileStream fsTXT = new FileStream(sfdDecompress.FileName, FileMode.Create); StreamWriter swTXT = new StreamWriter(fsTXT, System.Text.Encoding.Default); string sRecord = ""; IPAddress ipRecord; int iOffset = 0; byte[] abOffset = new byte[4]; for (int i = iFI; i < iLI + 7; i += 7) { //获取 IP 信息偏移 Array.Copy(m_abQQWry, i + 4, abOffset, 0, 3); iOffset = BitConverter.ToInt32(abOffset, 0); //起始 IP(终止 IP 在索引指向处) ipRecord = new IPAddress(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(BitConverter.ToInt32(m_abQQWry, i)))); sRecord = ipRecord.ToString() + " - "; //获取 IP 信息条目 sRecord += GetAddress(iOffset, (m_abQQWry[iOffset + 4] > 0x02), true); swTXT.WriteLine(sRecord.TrimEnd("/t".ToCharArray())); } swTXT.Flush(); fsTXT.Flush(); swTXT.Close(); fsTXT.Close(); MessageBox.Show("文件已解压到 '" + sfdDecompress.FileName + "'!"); } catch (Exception ex) { MessageBox.Show(ex.ToString()); } }
代码在VS2010+Windows 7下测试成功。
完整的代码在这里下载:
/Uploads/Images/Content/202010/10/de2c3679d7baf547b54c0e776654a177.gif
相关文章推荐
- 纯真IP数据库查询(C#源代码)
- C#读取QQ纯真IP数据库
- C#读取QQ纯真IP数据库QQWry.Dat的代码
- C#读取纯真IP数据库
- C#读取纯真IP数据库的代码
- 【转】C#读取QQ纯真IP数据库中的数据
- C#读取纯真IP数据库
- C# 读取纯真IP数据库QQWry.dat获取地区信息
- 纯真IP数据库查询模块源代码参考(C#)
- C# 读取纯真IP数据库QQWry.dat获取地区信息
- 纯真IP数据库查询,C#.NET实现。
- C#读取纯真IP数据库的代码
- C#读取纯真IP数据库的代码
- delphi读取纯真IP数据库
- PHP获取IP及地区信息(纯真IP数据库)
- [转]纯真IP数据库格式详解
- 纯真IP数据库的应用 IP地址转化成十进制
- 基于C# 语言的两个html解析器
- 使用纯真IP数据库定位IP地址所在地
- 纯真IP数据库导入mysql