QQWry.datIP地址库的查询程序

2024-01-17 07:48
文章标签 程序 查询 地址 qqwry datip

本文主要是介绍QQWry.datIP地址库的查询程序,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

改写了QQIP地址库的查询程序,学习了怎么操作文件。
也学会了正确使用tar命令。
本来想把 ip.d ip.php 和 QQWry.dat 文件打包成 a.tgz的,
结果把命令写成了 tar czf ip.d ip.php QQWry.dat a.tgz
把辛辛苦苦的写的程序给覆盖了:(
重新写了一遍,发现还是很快的。

[code]/**
* QQWry.dat IP地址库的查找程序
* Edit by Liu Dehong @ 2007/08/08
* Version: 1.0.0
*
* 改编自 马秉尧 的PHP程序
* QQWry.dat 来自于 CZ88.net
* Q数据库的格式参考:http://www.pconline.com.cn/pcedu/empolder/gj/java/0505/612860.html
*/

import std.stdio;
import std.stream;
import std.string;
import std.math;

extern(C)
{
uint ntohl(uint);
uint inet_addr(char *cp);
uint htonl(uint hostlong);
char* inet_ntoa(in_addr);
struct in_addr
{
uint s_addr;
}
}

uint ip2long(char[] ip)
{
return ntohl(inet_addr(toStringz(ip)));
}

char[] long2ip(ulong ip)
{
in_addr myaddr;
myaddr.s_addr = htonl(ip);
return toString(inet_ntoa(myaddr)).dup;
}

class IpLocation
{
private File m_file;
private uint m_firstip; // 第一条IP记录的偏移地址
private uint m_lastip; // 最后一条IP记录的偏移地址
private uint m_totalip; // IP记录的总条数(不包含版本信息记录)

static assert (int.sizeof == 4);
static assert (uint.sizeof == 4);
static assert (long.sizeof == 8);

/* 从文件读取4个字节,返回整型数
*/
uint get4Byte()
{
uint i;
m_file.read(i);
return i;
}

/* 从文件读取3个字节的数据,返回整型数
*/
uint get3Byte()
{
ubyte c;
uint sum;
int[3] pow = [1, 256, 256*256];
/**
* 如读取的是 2 34 56 ,则结果是 2 + 34*256 + 56*256*256
*/
for (int i; i < 3; i++)
{
m_file.read(c);
sum += c * pow[i];
}
return sum;
}

/* 返回读取的字符串
*/
char[] getString()
{
debug(1) writefln("GetString's pos: %d(%X)", m_file.position, m_file.position);

ubyte c;
char[] str = new char[100]; // guess
int i;
for (i = 0; true; i++)
{
m_file.read(c);
if (c == 0) // 字符串按照C格式保存,以\0结束
break;
if (i == str.length)
str.length = str.length * 2;
str[i] = c;
}
str.length = i;
return str;
}

/* 返回地区信息
*/
char[] getArea()
{
debug(1) writefln("GetArea's pos: %d(%X)", m_file.position, m_file.position);

ubyte flag; // 标志字节
char[] area;

m_file.read(flag);
switch (flag)
{
case 0:
// 没有区域信息
area = "";
break;

case 1:
case 2:
// 标志字节为1或2,表示区域信息被重定向
m_file.position(get3Byte());
area = getString();
break;

default:
// 否则,表示区域信息没有被重定向
area = cast(char)flag ~ getString(); // flag 是一个字符
break;
}
return area;
}

/* 根据所给 IP 地址或域名返回所在地区信息
* 索取区按照地址从小到大排列,用折半算法查找
*/
string[string] getLocation(char[] addr)
{
if ( ! m_file.readable)
return null;

/* 查找纪录区的位置
*/
uint l = 0; // 搜索的下边界
uint u = m_totalip; // 搜索的上边界
uint findip = m_lastip; // 如果没有找到就返回最后一条IP记录(QQWry.Dat的版本信息)
uint i;

uint beginip;
uint endip;

auto ip_t = ip2long(addr);

while (l <= u) // 当上边界小于下边界时,查找失败
{
i = std.math.lround((l + u) / 2);
m_file.position(m_firstip + i * 7);
m_file.read(beginip);
if (ip_t < beginip)
{
u = i - 1;
}
else
{
m_file.position(get3Byte());
m_file.read(endip);
if (ip_t > endip)
{
l = i + 1;
}
else
{
findip = m_firstip + i * 7; // find it
break;
}
}
}

debug(1) writefln("Findip is: %d(%#X)", findip, findip);

/* 获取查找到的IP地理位置信息
*/

string[string] location;
m_file.position(findip);
location["beginip"] = long2ip(get4Byte()); // 用户IP所在范围的开始地址

auto offset = get3Byte();
m_file.position(offset);
location["endip"] = long2ip(get4Byte()); // 用户IP所在范围的结束地址

ubyte flag1, flag2; // 标志字节
m_file.read(flag1);
switch (flag1)
{
case 1:
// 标志字节为1,表示国家和区域信息都被同时重定向
auto countryOffset = get3Byte(); // 重定向地址
m_file.position(countryOffset);
m_file.read(flag2); // 标志字节
switch (flag2)
{
case 2:
// 标志字节为2,表示国家信息又被重定向
m_file.position(get3Byte());
location["country"] = getString();
m_file.position(countryOffset + 4);
location["area"] = getArea();
break;

default:
// 否则,表示国家信息没有被重定向
location["country"] = cast(char)flag2 ~ getString(); // flag2 是一个字符
location["area"] = getArea();
break;
}
break;

case 2:
// 标志字节为2,表示国家信息被重定向
m_file.position(get3Byte());
location["country"] = getString();
m_file.position(offset + 8); // IP地址(4B) + 定向模式(1B) + 偏移地址(3B)
location["area"] = getArea();
break;

default:
// 否则,表示国家信息没有被重定向
location["country"] = cast(char)flag1 ~ getString(); // flag1是一个字符
location["area"] = getArea();
break;
}

debug(1) writefln("Flag1&2 : %d %d", flag1, flag2);

if (location["country"] == " CZ88.NET") // CZ88.NET表示没有有效信息
{
location["country"] = "unkown";
}
if (location["area"] == " CZ88.NET")
{
location["area"] = "";
}
return location;
}

/**
* 构造函数,打开 QQWry.Dat 文件并初始化类中的信息
*/
this(char[] filename = "QQWry.Dat")
{
m_file = new File(filename);
m_firstip = get4Byte();
m_lastip = get4Byte();
m_totalip = (m_lastip - m_firstip) / 7;
}

uint firstip()
{
return m_firstip;
}
uint lastip()
{
return m_lastip;
}
uint totalip()
{
return m_totalip;
}
}

void main()
{

auto ipObj = new IpLocation;

writefln("First IP is: %s", ipObj.firstip);
writefln("Last IP is : %s", ipObj.lastip);
writefln("Total ip is: %s", ipObj.totalip);

string[] myips = [
"0.255.255.255",
"0.255.255.255",
"1.255.255.255",
"4.10.255.255",
"4.10.255.255",
"4.19.77.255",
"59.57.7.206",
"222.79.141.30",
"211.100.32.245",
"202.106.184.145",
"202.205.82.122",
"0.1.163.136",
];

string[string] loc;
foreach (int k, string v; myips)
{
loc = ipObj.getLocation(v);
printf("%*s in [%.*s ~ %.*s]"\n, v, loc["beginip"], loc["endip"]);
printf("Country: %-20.*s Area: %-20.*s"\n, loc["country"], loc["area"]);
}
}
[/code]

这篇关于QQWry.datIP地址库的查询程序的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/615338

相关文章

从入门到精通MySQL联合查询

《从入门到精通MySQL联合查询》:本文主要介绍从入门到精通MySQL联合查询,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下... 目录摘要1. 多表联合查询时mysql内部原理2. 内连接3. 外连接4. 自连接5. 子查询6. 合并查询7. 插入查询结果摘要前面我们学习了数据库设计时要满

MySQL查询JSON数组字段包含特定字符串的方法

《MySQL查询JSON数组字段包含特定字符串的方法》在MySQL数据库中,当某个字段存储的是JSON数组,需要查询数组中包含特定字符串的记录时传统的LIKE语句无法直接使用,下面小编就为大家介绍两种... 目录问题背景解决方案对比1. 精确匹配方案(推荐)2. 模糊匹配方案参数化查询示例使用场景建议性能优

mysql表操作与查询功能详解

《mysql表操作与查询功能详解》本文系统讲解MySQL表操作与查询,涵盖创建、修改、复制表语法,基本查询结构及WHERE、GROUPBY等子句,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随... 目录01.表的操作1.1表操作概览1.2创建表1.3修改表1.4复制表02.基本查询操作2.1 SE

MySQL数据库的内嵌函数和联合查询实例代码

《MySQL数据库的内嵌函数和联合查询实例代码》联合查询是一种将多个查询结果组合在一起的方法,通常使用UNION、UNIONALL、INTERSECT和EXCEPT关键字,下面:本文主要介绍MyS... 目录一.数据库的内嵌函数1.1聚合函数COUNT([DISTINCT] expr)SUM([DISTIN

XML重复查询一条Sql语句的解决方法

《XML重复查询一条Sql语句的解决方法》文章分析了XML重复查询与日志失效问题,指出因DTO缺少@Data注解导致日志无法格式化、空指针风险及参数穿透,进而引发性能灾难,解决方案为在Controll... 目录一、核心问题:从SQL重复执行到日志失效二、根因剖析:DTO断裂引发的级联故障三、解决方案:修复

mysql查询使用_rowid虚拟列的示例

《mysql查询使用_rowid虚拟列的示例》MySQL中,_rowid是InnoDB虚拟列,用于无主键表的行ID查询,若存在主键或唯一列,则指向其,否则使用隐藏ID(不稳定),推荐使用ROW_NUM... 目录1. 基本查询(适用于没有主键的表)2. 检查表是否支持 _rowid3. 注意事项4. 最佳实

MySQL存储过程之循环遍历查询的结果集详解

《MySQL存储过程之循环遍历查询的结果集详解》:本文主要介绍MySQL存储过程之循环遍历查询的结果集,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言1. 表结构2. 存储过程3. 关于存储过程的SQL补充总结前言近来碰到这样一个问题:在生产上导入的数据发现

MySQL JSON 查询中的对象与数组技巧及查询示例

《MySQLJSON查询中的对象与数组技巧及查询示例》MySQL中JSON对象和JSON数组查询的详细介绍及带有WHERE条件的查询示例,本文给大家介绍的非常详细,mysqljson查询示例相关知... 目录jsON 对象查询1. JSON_CONTAINS2. JSON_EXTRACT3. JSON_TA

MYSQL查询结果实现发送给客户端

《MYSQL查询结果实现发送给客户端》:本文主要介绍MYSQL查询结果实现发送给客户端方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录mysql取数据和发数据的流程(边读边发)Sending to clientSending DataLRU(Least Rec

MySQL复杂SQL之多表联查/子查询详细介绍(最新整理)

《MySQL复杂SQL之多表联查/子查询详细介绍(最新整理)》掌握多表联查(INNERJOIN,LEFTJOIN,RIGHTJOIN,FULLJOIN)和子查询(标量、列、行、表子查询、相关/非相关、... 目录第一部分:多表联查 (JOIN Operations)1. 连接的类型 (JOIN Types)