您的位置:首页 > 数据库

读取纯真IP数据库C++源代码

2016-09-01 22:41 453 查看
头文件:

#pragma once;  

#include <string>  

  

const int INDEX_LENGTH = 7;        // 一个索引包含4字节的起始IP和3字节的IP记录偏移,共7字节  

const int IP_LENGTH = 4;  

const int OFFSET_LENGTH = 3;  

  

enum {  

 REDIRECT_MODE_1 = 0x01,    // 重定向模式1 偏移量后无地区名  

 REDIRECT_MODE_2 = 0x02,    // 重定向模式2 偏移量后有地区名  

};  

  

class CIpFinder  

{  

public:  

    CIpFinder();  

    CIpFinder(const char* pszFileName);  

    ~CIpFinder();  

  

    // 获取ip国家名、地区名  

    void GetAddressByIp(unsigned long ipValue, std::string& strCountry, std::string& strLocation) const;  

    void GetAddressByIp(const char* pszIp, std::string& strCountry, std::string& strLocation) const;  

    void GetAddressByOffset(unsigned long ulOffset, std::string& strCountry, std::string& strLocation) const;  

  

    unsigned long GetString(std::string& str, unsigned long indexStart) const;  

    unsigned long GetValue3(unsigned long indexStart) const;  

    unsigned long GetValue4(unsigned long indexStart) const;  

  

    // 转换  

    unsigned long IpString2IpValue(const char *pszIp) const;  

    void IpValue2IpString(unsigned long ipValue, char* pszIpAddress, int nMaxCount) const;  

    bool IsRightIpString(const char* pszIp) const;  

  

    // 输出数据  

    unsigned long OutputData(const char* pszFileName, unsigned long ulIndexStart = 0, unsigned long ulIndexEnd = 0) const;  

    unsigned long OutputDataByIp(const char* pszFileName, unsigned long ipValueStart, unsigned long ipValueEnd) const;  

    unsigned long OutputDataByIp(const char* pszFileName, const char* pszStartIp, const char* pszEndIp) const;  

  

    unsigned long SearchIp(unsigned long ipValue, unsigned long indexStart = 0, unsigned long indexEnd = 0) const;  

    unsigned long SearchIp(const char* pszIp, unsigned long indexStart = 0, unsigned long indexEnd = 0) const;  

  

    bool Open(const char* pszFileName);  

private:  

    FILE *m_fpIpDataFile;            // IP数据库文件  

    unsigned long m_indexStart;    // 起始索引偏移  

    unsigned long m_indexEnd;        // 结束索引偏移  

};  

实现文件:

#include "h1.h"  

// ============================================================================  

// ==============================================================================  

CIpFinder::CIpFinder()  

{  

}  

  

// ============================================================================  

// ==============================================================================  

CIpFinder::CIpFinder(const char *pszFileName)  

{  

    this->Open(pszFileName);  

}  

  

// ============================================================================  

//    打开数据库文件  

// ==============================================================================  

bool CIpFinder::Open(const char *pszFileName)  

{  

    m_fpIpDataFile = fopen(pszFileName, "rb");  

    if (!m_fpIpDataFile) {  

        return false;  

    }  

  

    // IP头由两个十六进制4字节偏移量构成,分别为索引开始,和索引结束  

    m_indexStart = this->GetValue4(0);  

    m_indexEnd = this->GetValue4(4);  

    return true;  

}  

  

// ============================================================================  

// ==============================================================================  

CIpFinder::~CIpFinder()  

{  

    fclose(m_fpIpDataFile);  

}  

  

// ============================================================================  

//    根据IP地址字符串返回其十六进制值(4字节)  

// ============================================================================  

unsigned long CIpFinder::IpString2IpValue(const char *pszIp) const  

{  

    if (!this->IsRightIpString(pszIp)) {  

        return 0;  

    }  

    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~  

    int nNum = 0;            // 每个段数值  

    const char *pBeg = pszIp;  

    const char *pPos = NULL;  

    unsigned long ulIp = 0; // 整个IP数值  

    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~  

  

    pPos = strchr(pszIp, '.');  

    while (pPos != NULL) {  

        nNum = atoi(pBeg);  

        ulIp += nNum;  

        ulIp *= 0x100;  

        pBeg = pPos + 1;  

        pPos = strchr(pBeg, '.');  

    }  

  

    nNum = atoi(pBeg);  

    ulIp += nNum;  

    return ulIp;  

}  

  

// ============================================================================  

//    根据ip值获取字符串(由点分割)  

// ============================================================================  

void CIpFinder::IpValue2IpString(unsigned long ipValue,  

                                 char *pszIpAddress,  

                                 int nMaxCount) const  

{  

    if (!pszIpAddress) {  

        return;  

    }  

  

    _snprintf(pszIpAddress, nMaxCount, "%d.%d.%d.%d", (ipValue & 0xFF000000) >> 24,  

              (ipValue & 0x00FF0000) >> 16, (ipValue & 0x0000FF00) >> 8,ipValue & 0x000000FF);  

    pszIpAddress[nMaxCount - 1] = 0;  

}  

  

// ============================================================================  

//    根据指定IP(十六进制值),返回其在索引段中的位置(索引)  

//    ulIndexStart和ulIndexEnd可以指定搜索范围 均为0表示搜索全部  

// ============================================================================  

unsigned long CIpFinder::SearchIp(unsigned long ipValue,  

                                  unsigned long indexStart,  

                                  unsigned long indexEnd) const  

{  

    if (!m_fpIpDataFile) {  

        return 0;  

    }  

  

    if (0 == indexStart) {  

        indexStart = m_indexStart;  

    }  

  

    if (0 == indexEnd) {  

        indexEnd = m_indexEnd;  

    }  

  

    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  

    unsigned long indexLeft = indexStart;  

    unsigned long indexRight = indexEnd;  

  

    // 先除后乘是为了保证mid指向一个完整正确的索引  

    unsigned long indexMid = (indexRight - indexLeft) / INDEX_LENGTH / 2 * INDEX_LENGTH + indexLeft;  

  

    // 起始Ip地址(如172.23.0.0),他和Ip记录中的Ip地址(如172.23.255.255)构成一个Ip范围,在这个范围内的Ip都可以由这条索引来获取国家、地区  

    unsigned long ulIpHeader = 0;  

    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  

  

    do  

    {  

        ulIpHeader = this->GetValue4(indexMid);  

        if (ipValue < ulIpHeader) {  

            indexRight = indexMid;  

            indexMid = (indexRight - indexLeft) /    INDEX_LENGTH / 2 * INDEX_LENGTH + indexLeft;  

        } else {  

            indexLeft = indexMid;  

            indexMid = (indexRight - indexLeft) /    INDEX_LENGTH / 2 * INDEX_LENGTH + indexLeft;  

        }  

    } while (indexLeft < indexMid);            // 注意是根据mid来进行判断  

  

    // 只要符合范围就可以,不需要完全相等  

    return indexMid;  

}  

  

// ============================================================================  

// ==============================================================================  

unsigned long CIpFinder::SearchIp(const char *pszIp,  

                                  unsigned long indexStart,  

                                  unsigned long indexEnd) const  

{  

    if (!this->IsRightIpString(pszIp)) {  

        return 0;  

    }  

    return this->SearchIp(this->IpString2IpValue(pszIp), indexStart,  

                          indexEnd);  

}  

  

// ==========================================================================================================  

//    从指定位置获取一个十六进制的数 (读取3个字节, 主要用于获取偏移量, 与效率紧密相关的函数,尽可能优化)  

// ==========================================================================================================  

unsigned long CIpFinder::GetValue3(unsigned long indexStart) const  

{  

    if (!m_fpIpDataFile) {  

        return 0;  

    }  

  

    //~~~~~~~~~~~~~~~~~~~~  

    int nVal[3];  

    unsigned long ulValue = 0;  

    //~~~~~~~~~~~~~~~~~~~~  

  

    fseek(m_fpIpDataFile, indexStart, SEEK_SET);  

    for (int i = 0; i < 3; i++) {  

  

        // 过滤高位,一次读取一个字符  

        nVal[i] = fgetc(m_fpIpDataFile) & 0x000000FF;  

    }  

  

    for (int j = 2; j >= 0; --j) {  

  

        // 因为读取多个16进制字符,叠加  

        ulValue = ulValue * 0x100 + nVal[j];  

    }  

    return ulValue;  

}  

  

// ==========================================================================================================  

//    从指定位置获取一个十六进制的数 (读取4个字节, 主要用于获取IP值, 与效率紧密相关的函数,尽可能优化)  

// ==========================================================================================================  

unsigned long CIpFinder::GetValue4(unsigned long indexStart) const  

{  

    if (!m_fpIpDataFile) {  

        return 0;  

    }  

  

    //~~~~~~~~~~~~~~~~~~~~  

    int nVal[4];  

    unsigned long ulValue = 0;  

    //~~~~~~~~~~~~~~~~~~~~  

  

    fseek(m_fpIpDataFile, indexStart, SEEK_SET);  

    for (int i = 0; i < 4; i++) {  

  

        // 过滤高位,一次读取一个字符  

        nVal[i] = fgetc(m_fpIpDataFile) & 0x000000FF;  

    }  

  

    for (int j = 3; j >= 0; --j) {  

  

        // 因为读取多个16进制字符,叠加  

        ulValue = ulValue * 0x100 + nVal[j];  

    }  

    return ulValue;  

}  

  

// ============================================================================  

//    从指定位置获取字符串  

// ============================================================================  

unsigned long CIpFinder::GetString(std::string &str, unsigned long indexStart) const  

{  

    if (!m_fpIpDataFile) {  

        return 0;  

    }  

  

    str.erase(0, str.size());  

  

    fseek(m_fpIpDataFile, indexStart, SEEK_SET);  

    //~~~~~~~~~~~~~~~~~~~~~~  

    int nChar = fgetc(m_fpIpDataFile);  

    unsigned long ulCount = 1;  

    //~~~~~~~~~~~~~~~~~~~~~~  

  

      

  

    // 读取字符串,直到遇到0x00为止  

     while (nChar != 0x00) {  

  

        // 依次放入用来存储的字符串空间中  

        str += static_cast<char>(nChar);  

        ++ulCount;  

        nChar = fgetc(m_fpIpDataFile);  

    }  

  

    // 返回字符串长度  

    return ulCount;  

}  

  

// ============================================================================  

//    通过指定的偏移量来获取ip记录中的国家名和地区名,偏移量可由索引获取  

//    ulOffset为Ip记录偏移量  

// ============================================================================  

void CIpFinder::GetAddressByOffset(unsigned long ulOffset,  

                                   std::string &strCountry,  

                                   std::string &strLocation) const  

{  

    if (!m_fpIpDataFile) {  

        return;  

    }  

  

    // 略去4字节Ip地址  

    ulOffset += IP_LENGTH;  

    fseek(m_fpIpDataFile, ulOffset, SEEK_SET);  

  

    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  

    // 读取首地址的值  

    int nVal = (fgetc(m_fpIpDataFile) & 0x000000FF);  

    unsigned long ulCountryOffset = 0;    // 真实国家名偏移  

    unsigned long ulLocationOffset = 0; // 真实地区名偏移  

    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  

  

    // 为了节省空间,相同字符串使用重定向,而不是多份拷贝  

    if (REDIRECT_MODE_1 == nVal) {  

  

        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  

        // 重定向1类型  

        unsigned long ulRedirect = this->GetValue3(ulOffset + 1); // 重定向偏移  

                                                                    ///  

        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  

  

        fseek(m_fpIpDataFile, ulRedirect, SEEK_SET);  

  

        if ((fgetc(m_fpIpDataFile) & 0x000000FF) == REDIRECT_MODE_2) {  

  

            // 混合类型1,重定向1类型进入后遇到重定向2类型   

            // 0x01 1字节  

            // 偏移量 3字节 -----> 0x02 1字节   

            //                     偏移量 3字节 -----> 国家名  

            //                     地区名  

            ulCountryOffset = this->GetValue3(ulRedirect + 1);  

            this->GetString(strCountry, ulCountryOffset);  

            ulLocationOffset = ulRedirect + 4;  

        } else {  

  

            // 单纯的重定向模式1  

            // 0x01 1字节  

            // 偏移量 3字节 ------> 国家名  

            //                      地区名  

            ulCountryOffset = ulRedirect;  

            ulLocationOffset = ulRedirect + this->GetString(strCountry,  

                                                            ulCountryOffset);  

        }  

    } else if (REDIRECT_MODE_2 == nVal) {  

  

        // 重定向2类型  

        // 0x02 1字节  

        // 国家偏移 3字节 -----> 国家名  

        // 地区名  

        ulCountryOffset = this->GetValue3(ulOffset + 1);  

        this->GetString(strCountry, ulCountryOffset);  

  

        ulLocationOffset = ulOffset + 4;  

    } else {  

  

        // 最简单的情况 没有重定向  

        // 国家名  

        // 地区名  

        ulCountryOffset = ulOffset;  

        ulLocationOffset = ulCountryOffset + this->GetString(strCountry,  

                                                             ulCountryOffset);  

    }  

  

    // 读取地区  

    fseek(m_fpIpDataFile, ulLocationOffset, SEEK_SET);  

    if ((fgetc(m_fpIpDataFile) & 0x000000FF) == REDIRECT_MODE_2  

    || (fgetc(m_fpIpDataFile) & 0x000000FF) == REDIRECT_MODE_1) {  

  

        // 混合类型2(最复杂的情形,地区也重定向)  

        // 0x01 1字节  

        // 偏移量 3字节 ------> 0x02 1字节  

        //                      偏移量 3字节 -----> 国家名  

        //                      0x01 or 0x02 1字节  

        //                      偏移量 3字节 ----> 地区名 偏移量为0表示未知地区  

        ulLocationOffset = this->GetValue3(ulLocationOffset + 1);  

    }  

  

    this->GetString(strLocation, ulLocationOffset);  

}  

  

// ============================================================================  

//    根据十六进制ip获取国家名地区名  

// ============================================================================  

void CIpFinder::GetAddressByIp(unsigned long ipValue,  

                               std::string &strCountry,  

                               std::string &strLocation) const  

{  

    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  

    unsigned long ulIndexOffset = this->SearchIp(ipValue);  

    unsigned long ulRecordOffset = this->GetValue3(ulIndexOffset + IP_LENGTH);  

    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  

  

    this->GetAddressByOffset(ulRecordOffset, strCountry, strLocation);  

}  

  

// ============================================================================  

//    根据ip字符串获取国家名地区名  

// ============================================================================  

void CIpFinder::GetAddressByIp(const char *pszIp,  

                               std::string &strCountry,  

                               std::string &strLocation) const  

{  

    if (!this->IsRightIpString(pszIp)) {  

        return;  

    }  

    this->GetAddressByIp(this->IpString2IpValue(pszIp), strCountry, strLocation);  

}  

  

// ============================================================================  

//    将ip数据导出,start和end界定导出范围, 可通过SearchIp来获取  

// ============================================================================  

unsigned long CIpFinder::OutputData(const char *pszFileName,  

                                    unsigned long indexStart,  

                                    unsigned long indexEnd) const  

{  

    if (!m_fpIpDataFile || !pszFileName) {  

        return 0;  

    }  

  

    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  

    FILE *fpOut = fopen(pszFileName, "wb");  

    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  

  

    if (!fpOut) {  

        return 0;  

    }  

  

    if (0 == indexStart) {  

        indexStart = m_indexStart;  

    }  

  

    if (0 == indexEnd) {  

        indexEnd = m_indexEnd;  

    }  

  

    //~~~~~~~~~~~~~~~~~~~~~~~~  

    char szEndIp[255];  

    char szStartIp[255];  

    std::string strCountry;  

    std::string strLocation;  

    unsigned long ulCount = 0;  

    unsigned long ipValueEnd = 0;  

    unsigned long ipValueStart = 0;  

    //~~~~~~~~~~~~~~~~~~~~~~~~  

  

    for (unsigned long i = indexStart; i < indexEnd; i += INDEX_LENGTH) {  

  

        // 获取IP段的起始IP和结束IP, 起始IP为索引部分的前4位16进制  

        // 结束IP在IP信息部分的前4位16进制中,靠索引部分指定的偏移量找寻  

        ipValueStart = this->GetValue4(i);  

        ipValueEnd = this->GetValue4(this->GetValue3(i + IP_LENGTH));  

  

        // 导出IP信息,格式是 起始IP/t结束IP/t国家位置/t地域位置/n  

        this->IpValue2IpString(ipValueStart, szStartIp, sizeof(szStartIp));  

        this->IpValue2IpString(ipValueEnd, szEndIp, sizeof(szEndIp));  

        this->GetAddressByOffset(this->GetValue3(i + IP_LENGTH), strCountry,  

                                 strLocation);  

        fprintf(fpOut, "%s/t%s/t%s/t%s/n", szStartIp, szEndIp,  

                strCountry.c_str(), strLocation.c_str());  

        ulCount++;  

    }  

  

    fclose(fpOut);  

  

    // 返回导出总条数  

    return ulCount;  

}  

  

// ============================================================================  

//    通过ip值界定导出范围  

// ==============================================================================  

unsigned long CIpFinder::OutputDataByIp(const char *pszFileName,  

                                        unsigned long ipValueStart,  

                                        unsigned long ipValueEnd) const  

{  

    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  

    unsigned long indexStart = this->SearchIp(ipValueStart);  

    unsigned long indexEnd = this->SearchIp(ipValueEnd);  

    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  

  

    return this->OutputData(pszFileName, indexStart, indexEnd);  

}  

  

// ============================================================================  

//    通过ip字符串界定导出范围  

// ==============================================================================  

unsigned long CIpFinder::OutputDataByIp(const char *pszFileName,  

                                        const char *pszStartIp,  

                                        const char *pszEndIp) const  

{  

    if (!this->IsRightIpString(pszStartIp) || !this->IsRightIpString(pszEndIp)) {  

        return 0;  

    }  

    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  

    unsigned long ipValueEnd = this->IpString2IpValue(pszEndIp);  

    unsigned long ipValueStart = this->IpString2IpValue(pszStartIp);  

    unsigned long indexEnd = this->SearchIp(ipValueEnd);  

    unsigned long indexStart = this->SearchIp(ipValueStart);  

    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  

  

    return this->OutputData(pszFileName, indexStart, indexEnd);  

}  

  

// ============================================================================  

//    判断给定IP字符串是否是合法的ip地址  

// ==============================================================================  

bool CIpFinder::IsRightIpString(const char* pszIp) const  

{  

    if (!pszIp) {  

        return false;  

    }  

  

    int nLen = strlen(pszIp);  

    if (nLen < 7) {  

  

        // 至少包含7个字符"0.0.0.0"  

        return false;  

    }  

  

    for (int i = 0; i < nLen; ++i) {  

        if (!isdigit(pszIp[i]) && pszIp[i] != '.') {  

            return false;  

        }  

  

        if (pszIp[i] == '.') {  

            if (0 == i) {  

                if (!isdigit(pszIp[i + 1])) {  

                    return false;  

                }  

            } else if (nLen - 1 == i) {  

                if (!isdigit(pszIp[i - 1])) {  

                    return false;  

                }  

            } else {  

                if (!isdigit(pszIp[i - 1]) || !isdigit(pszIp[i + 1])) {  

                    return false;  

                }  

            }  

        }  

    }  

    return true;  

}  

main文件:

#include"h1.h"

#include<iostream>

using namespace std;

int main()

{
CIpFinder CFinder=CIpFinder();
CFinder.Open("C:\\Users\\yangpeng\\Documents\\visual studio 2012\\Projects\\ConsoleApplication2\\qqwry.dat");
string country,location;
CFinder.GetAddressByIp("116.77.91.144",country,location);
cout<<country<<location<< endl;

system("pause");
return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: