高春辉做了一个功德无量的事情,整理了一份高质量的 IP 库,http://tool.17mon.cn/ipdb.html,官方给出了 php 版本的解析函数,但是没有 c++ 的,倒是有人写了一个 php c 扩展,https://github.com/shukean/mon…,不过太长了。。
于是自己写了个 c++ 的
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <string> #include <vector> #include <fstream> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <assert.h> class IP17MON { public: bool init(const std::string strPathToDataFile = "./17monipdb.dat") { printf("Opening %s\n", strPathToDataFile.c_str()); std::ifstream ifDataFile(strPathToDataFile.c_str(), std::ios::binary); if (ifDataFile.is_open() == false) { printf("%m\n"); return false; } vecDataFile.assign(std::istreambuf_iterator<char>(ifDataFile), std::istreambuf_iterator<char>()); printf("Load %lu bytes success\n", vecDataFile.size()); unsigned int uiIndexLen = 0; memcpy(&uiIndexLen, &vecDataFile[0], 4); uiIndexLen = ntohl(uiIndexLen); //printf("index len %u\n", uiIndexLen); pIPIndex = &vecDataFile[4]; pIPData = &vecDataFile[uiIndexLen]; return true; } std::string find(const std::string strIP) { if (strIP.empty()) { return ""; } struct sockaddr_in stSockAddrInet = {0}; if(inet_aton(strIP.c_str(), &stSockAddrInet.sin_addr) == 0) { //printf("convert error\n"); return ""; } unsigned int uiIP = ntohl(stSockAddrInet.sin_addr.s_addr); //printf("ip %X\n", uiIP); int iFirst = atoi(strIP.c_str()); int iStart = 0; memcpy(&iStart, pIPIndex+(iFirst*4), 4); //printf("start %d\n", iStart); int iMaxComLen = pIPData - pIPIndex - 1024 - 4; //printf("max compare len %d\n", iMaxComLen); int iIndexOffset = -1; unsigned char ucIndexLength = 0; for (iStart = iStart * 8 + 1024; iStart < iMaxComLen; iStart += 8) { unsigned int uiCurrIP = 0; memcpy(&uiCurrIP, pIPIndex+iStart, 4); uiCurrIP = ntohl(uiCurrIP); //printf("curr %u looking %u\n", uiCurrIP, uiIP); if (uiCurrIP >= uiIP) { iIndexOffset = 0; memcpy(&iIndexOffset, pIPIndex+iStart+4, 3); memcpy(&ucIndexLength, pIPIndex+iStart+7, 1); break; } } //printf("index offset %u\n", iIndexOffset); //printf("index length %u\n", ucIndexLength); if (iIndexOffset == -1) { return ""; } std::string strRegion; char *pRegion = pIPData + iIndexOffset - 1024; strRegion.assign(pRegion, ucIndexLength); //printf("str region %s\n", strRegion.c_str()); return strRegion; } private: std::vector<char> vecDataFile; char *pIPIndex, *pIPData; }; int main() { IP17MON oIP17MON; assert(oIP17MON.init()); printf("%s -> %s\n", "14.17.22.40", oIP17MON.find("14.17.22.40").c_str()); return 0; }
效率方面,在我 cpu e5300, ram 4g ddr2 800, os ubuntu 14.04 的机器上,大约是每秒 150 万次