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的sql_mode可能会限制你的查询

《浅谈mysql的sql_mode可能会限制你的查询》本文主要介绍了浅谈mysql的sql_mode可能会限制你的查询,这个问题主要说明的是,我们写的sql查询语句违背了聚合函数groupby的规则... 目录场景:问题描述原因分析:解决方案:第一种:修改后,只有当前生效,若是mysql服务重启,就会失效;

MySQL多列IN查询的实现

《MySQL多列IN查询的实现》多列IN查询是一种强大的筛选工具,它允许通过多字段组合快速过滤数据,本文主要介绍了MySQL多列IN查询的实现,具有一定的参考价值,感兴趣的可以了解一下... 目录一、基础语法:多列 IN 的两种写法1. 直接值列表2. 子查询二、对比传统 OR 的写法三、性能分析与优化1.

Linux系统中配置静态IP地址的详细步骤

《Linux系统中配置静态IP地址的详细步骤》本文详细介绍了在Linux系统中配置静态IP地址的五个步骤,包括打开终端、编辑网络配置文件、配置IP地址、保存并重启网络服务,这对于系统管理员和新手都极具... 目录步骤一:打开终端步骤二:编辑网络配置文件步骤三:配置静态IP地址步骤四:保存并关闭文件步骤五:重

Linux配置IP地址的三种实现方式

《Linux配置IP地址的三种实现方式》:本文主要介绍Linux配置IP地址的三种实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录环境RedHat9第一种安装 直接配置网卡文件第二种方式 nmcli(Networkmanager command-line

mybatis-plus 实现查询表名动态修改的示例代码

《mybatis-plus实现查询表名动态修改的示例代码》通过MyBatis-Plus实现表名的动态替换,根据配置或入参选择不同的表,本文主要介绍了mybatis-plus实现查询表名动态修改的示... 目录实现数据库初始化依赖包配置读取类设置 myBATis-plus 插件测试通过 mybatis-plu

MySQL中实现多表查询的操作方法(配sql+实操图+案例巩固 通俗易懂版)

《MySQL中实现多表查询的操作方法(配sql+实操图+案例巩固通俗易懂版)》本文主要讲解了MySQL中的多表查询,包括子查询、笛卡尔积、自连接、多表查询的实现方法以及多列子查询等,通过实际例子和操... 目录复合查询1. 回顾查询基本操作group by 分组having1. 显示部门号为10的部门名,员

如何用java对接微信小程序下单后的发货接口

《如何用java对接微信小程序下单后的发货接口》:本文主要介绍在微信小程序后台实现发货通知的步骤,包括获取Access_token、使用RestTemplate调用发货接口、处理AccessTok... 目录配置参数 调用代码获取Access_token调用发货的接口类注意点总结配置参数 首先需要获取Ac

Linux虚拟机不显示IP地址的解决方法(亲测有效)

《Linux虚拟机不显示IP地址的解决方法(亲测有效)》本文主要介绍了通过VMware新装的Linux系统没有IP地址的解决方法,主要步骤包括:关闭虚拟机、打开VM虚拟网络编辑器、还原VMnet8或修... 目录前言步骤0.问题情况1.关闭虚拟机2.China编程打开VM虚拟网络编辑器3.1 方法一:点击还原VM

mysql关联查询速度慢的问题及解决

《mysql关联查询速度慢的问题及解决》:本文主要介绍mysql关联查询速度慢的问题及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录mysql关联查询速度慢1. 记录原因1.1 在一次线上的服务中1.2 最终发现2. 解决方案3. 具体操作总结mysql

基于Python开发PDF转Doc格式小程序

《基于Python开发PDF转Doc格式小程序》这篇文章主要为大家详细介绍了如何基于Python开发PDF转Doc格式小程序,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 用python实现PDF转Doc格式小程序以下是一个使用Python实现PDF转DOC格式的GUI程序,采用T