QQWry.datIP地址库的查询程序
改写了QQIP地址库的查询程序,学习了怎么操作文件。也学会了正确使用tar命令。
本来想把 ip.d ip.php 和 QQWry.dat 文件打包成 a.tgz的,
结果把命令写成了 tar czf ip.d ip.php QQWry.dat a.tgz
把辛辛苦苦的写的程序给覆盖了:(
重新写了一遍,发现还是很快的。
/** * 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); uinthtonl(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 pow = ; /** * 如读取的是 2 34 56 ,则结果是 2 + 34*256 + 56*256*256 */ for (int i; i < 3; i++) { m_file.read(c); sum += c * pow; } return sum; } /* 返回读取的字符串 */ char[] getString() { debug(1) writefln("GetString's pos: %d(%X)", m_file.position, m_file.position); ubyte c; char[] str = new char; // 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 = 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 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 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 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"]); }}
页:
[1]