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

相关文章

Java实现复杂查询优化的7个技巧小结

《Java实现复杂查询优化的7个技巧小结》在Java项目中,复杂查询是开发者面临的“硬骨头”,本文将通过7个实战技巧,结合代码示例和性能对比,手把手教你如何让复杂查询变得优雅,大家可以根据需求进行选择... 目录一、复杂查询的痛点:为何你的代码“又臭又长”1.1冗余变量与中间状态1.2重复查询与性能陷阱1.

MySQL中查询和展示LONGBLOB类型数据的技巧总结

《MySQL中查询和展示LONGBLOB类型数据的技巧总结》在MySQL中LONGBLOB是一种二进制大对象(BLOB)数据类型,用于存储大量的二进制数据,:本文主要介绍MySQL中查询和展示LO... 目录前言1. 查询 LONGBLOB 数据的大小2. 查询并展示 LONGBLOB 数据2.1 转换为十

使用SpringBoot+InfluxDB实现高效数据存储与查询

《使用SpringBoot+InfluxDB实现高效数据存储与查询》InfluxDB是一个开源的时间序列数据库,特别适合处理带有时间戳的监控数据、指标数据等,下面详细介绍如何在SpringBoot项目... 目录1、项目介绍2、 InfluxDB 介绍3、Spring Boot 配置 InfluxDB4、I

Go语言使用Gin处理路由参数和查询参数

《Go语言使用Gin处理路由参数和查询参数》在WebAPI开发中,处理路由参数(PathParameter)和查询参数(QueryParameter)是非常常见的需求,下面我们就来看看Go语言... 目录一、路由参数 vs 查询参数二、Gin 获取路由参数和查询参数三、示例代码四、运行与测试1. 测试编程路

基于Python编写自动化邮件发送程序(进阶版)

《基于Python编写自动化邮件发送程序(进阶版)》在数字化时代,自动化邮件发送功能已成为企业和个人提升工作效率的重要工具,本文将使用Python编写一个简单的自动化邮件发送程序,希望对大家有所帮助... 目录理解SMTP协议基础配置开发环境构建邮件发送函数核心逻辑实现完整发送流程添加附件支持功能实现htm

MySQL 数据库表与查询操作实战案例

《MySQL数据库表与查询操作实战案例》本文将通过实际案例,详细介绍MySQL中数据库表的设计、数据插入以及常用的查询操作,帮助初学者快速上手,感兴趣的朋友跟随小编一起看看吧... 目录mysql 数据库表操作与查询实战案例项目一:产品相关数据库设计与创建一、数据库及表结构设计二、数据库与表的创建项目二:员

Linux查询服务器 IP 地址的命令详解

《Linux查询服务器IP地址的命令详解》在服务器管理和网络运维中,快速准确地获取服务器的IP地址是一项基本但至关重要的技能,下面我们来看看Linux中查询服务器IP的相关命令使用吧... 目录一、hostname 命令:简单高效的 IP 查询工具命令详解实际应用技巧注意事项二、ip 命令:新一代网络配置全

C#控制台程序同步调用WebApi实现方式

《C#控制台程序同步调用WebApi实现方式》控制台程序作为Job时,需同步调用WebApi以确保获取返回结果后执行后续操作,否则会引发TaskCanceledException异常,同步处理可避免异... 目录同步调用WebApi方法Cls001类里面的写法总结控制台程序一般当作Job使用,有时候需要控制

Linux查询服务器系统版本号的多种方法

《Linux查询服务器系统版本号的多种方法》在Linux系统管理和维护工作中,了解当前操作系统的版本信息是最基础也是最重要的操作之一,系统版本不仅关系到软件兼容性、安全更新策略,还直接影响到故障排查和... 目录一、引言:系统版本查询的重要性二、基础命令解析:cat /etc/Centos-release详

MySQL慢查询工具的使用小结

《MySQL慢查询工具的使用小结》使用MySQL的慢查询工具可以帮助开发者识别和优化性能不佳的SQL查询,本文就来介绍一下MySQL的慢查询工具,具有一定的参考价值,感兴趣的可以了解一下... 目录一、启用慢查询日志1.1 编辑mysql配置文件1.2 重启MySQL服务二、配置动态参数(可选)三、分析慢查