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线上查询之前要性能调优的技巧及示例》文章介绍了查询优化的几种方法,包括使用索引、避免不必要的列和行、有效的JOIN策略、子查询和派生表的优化、查询提示和优化器提示等,这些方法可以帮助提高数... 目录避免不必要的列和行使用有效的JOIN策略使用子查询和派生表时要小心使用查询提示和优化器提示其他常

将java程序打包成可执行文件的实现方式

《将java程序打包成可执行文件的实现方式》本文介绍了将Java程序打包成可执行文件的三种方法:手动打包(将编译后的代码及JRE运行环境一起打包),使用第三方打包工具(如Launch4j)和JDK自带... 目录1.问题提出2.如何将Java程序打包成可执行文件2.1将编译后的代码及jre运行环境一起打包2

Ubuntu固定虚拟机ip地址的方法教程

《Ubuntu固定虚拟机ip地址的方法教程》本文详细介绍了如何在Ubuntu虚拟机中固定IP地址,包括检查和编辑`/etc/apt/sources.list`文件、更新网络配置文件以及使用Networ... 1、由于虚拟机网络是桥接,所以ip地址会不停地变化,接下来我们就讲述ip如何固定 2、如果apt安

SQL 中多表查询的常见连接方式详解

《SQL中多表查询的常见连接方式详解》本文介绍SQL中多表查询的常见连接方式,包括内连接(INNERJOIN)、左连接(LEFTJOIN)、右连接(RIGHTJOIN)、全外连接(FULLOUTER... 目录一、连接类型图表(ASCII 形式)二、前置代码(创建示例表)三、连接方式代码示例1. 内连接(I

在不同系统间迁移Python程序的方法与教程

《在不同系统间迁移Python程序的方法与教程》本文介绍了几种将Windows上编写的Python程序迁移到Linux服务器上的方法,包括使用虚拟环境和依赖冻结、容器化技术(如Docker)、使用An... 目录使用虚拟环境和依赖冻结1. 创建虚拟环境2. 冻结依赖使用容器化技术(如 docker)1. 创

轻松上手MYSQL之JSON函数实现高效数据查询与操作

《轻松上手MYSQL之JSON函数实现高效数据查询与操作》:本文主要介绍轻松上手MYSQL之JSON函数实现高效数据查询与操作的相关资料,MySQL提供了多个JSON函数,用于处理和查询JSON数... 目录一、jsON_EXTRACT 提取指定数据二、JSON_UNQUOTE 取消双引号三、JSON_KE

查询SQL Server数据库服务器IP地址的多种有效方法

《查询SQLServer数据库服务器IP地址的多种有效方法》作为数据库管理员或开发人员,了解如何查询SQLServer数据库服务器的IP地址是一项重要技能,本文将介绍几种简单而有效的方法,帮助你轻松... 目录使用T-SQL查询方法1:使用系统函数方法2:使用系统视图使用SQL Server Configu

使用Java实现获取客户端IP地址

《使用Java实现获取客户端IP地址》这篇文章主要为大家详细介绍了如何使用Java实现获取客户端IP地址,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 首先是获取 IP,直接上代码import org.springframework.web.context.request.Requ

Linux环境变量&&进程地址空间详解

《Linux环境变量&&进程地址空间详解》本文介绍了Linux环境变量、命令行参数、进程地址空间以及Linux内核进程调度队列的相关知识,环境变量是系统运行环境的参数,命令行参数用于传递给程序的参数,... 目录一、初步认识环境变量1.1常见的环境变量1.2环境变量的基本概念二、命令行参数2.1通过命令编程

MYSQL关联关系查询方式

《MYSQL关联关系查询方式》文章详细介绍了MySQL中如何使用内连接和左外连接进行表的关联查询,并展示了如何选择列和使用别名,文章还提供了一些关于查询优化的建议,并鼓励读者参考和支持脚本之家... 目录mysql关联关系查询关联关系查询这个查询做了以下几件事MySQL自关联查询总结MYSQL关联关系查询