本文主要是介绍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地址库的查询程序的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!