sofire 发表于 2013-2-5 00:48:43

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]
查看完整版本: QQWry.datIP地址库的查询程序