`
sofire
  • 浏览: 143973 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

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);
    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"]);
    }
}
  • IpLocation.zip (3.2 MB)
  • 描述: 包括:D语言的源程序,PHP版本的程序,QQWry的数据库文件和格式说明文件
  • 下载次数: 44
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics