|
读取纯真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 "ip.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;
- }
复制代码
|
|