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

头文件:

#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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
纯真IP数据库是一个常用的IP地理位置查询工具,用于根据IP地址查询对应的地区名。该数据库纯真网络发布,包含了大量的IP地址段及其对应的地理位置信息。使用PHP编程语言可以通过以下步骤来查询IP地址对应的地区名: 1. 首先,需要将纯真IP数据库文件(通常是QQWry.dat)下载并存储在服务器上。 2. 使用PHP的文件操作函数(例如fopen和fread)来打开并读取数据库文件,获取其中的内容。 3. 解析读取到的数据库内容,根据IP地址对应的起始和结束位置,使用二分查找等算法来确定目标IP地址所在的位置。 4. 根据确定的位置,提取出对应的地区名信息。 以下是一个简单的示例代码,实现了根据IP地址查询地区名的功能: ```php <?php function searchRegion($ip) { $path = 'QQWry.dat'; $fp = fopen($path, 'rb'); $content = fread($fp, filesize($path)); $start = unpack('V', $content[0] . $content[1] . $content[2] . $content[3])[1]; $end = unpack('V', $content[4] . $content[5] . $content[6] . $content[7])[1]; $ip = pack('N', intval(ip2long($ip))); while ($start <= $end) { $mid = floor(($start + $end) / 2); fseek($fp, $mid * 7); $data = fread($fp, 7); $ipStart = implode('.', array_map('ord', str_split(substr($data, 0, 4)))); if ($ip < $ipStart) { $end = $mid - 1; } else { $offset = unpack('V', substr($data, 4, 3) . chr(0))[1]; if ($offset == 0) { return '未知地区'; } fseek($fp, $offset); $data = fread($fp, 4); if (substr($data, 0, 1) == chr(0x01)) { $offset = unpack('V', substr($data, 1, 3))[1]; fseek($fp, $offset); $data = fread($fp, 3); } return iconv('gbk', 'utf-8', $data); } } return '未知地区'; } ``` 以上代码使用了二分查找算法,在纯真IP数据库中查找目标IP地址所在位置,并返回对应的地区名(使用了GBK到UTF-8的字符编码转换)。当查询的IP地址在数据库中不存在时,将返回"未知地区"。 希望以上解答可以帮助到您!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值