纯真ip数据库格式详解
纯真IP数据库是一种常用的IP地址归属地查询工具,以下是纯真IP数据库格式的详解:
- 下载纯真IP数据库
在纯真IP数据库官网(http://www.cz88.net/)上下载最新版的IP数据库,通常包括两个文件:QQWry.dat和QQWry.idx。
- IP数据库格式
纯真IP数据库采用的是固定长度的数据格式,每条记录的长度为7个字节,格式如下:
| 4字节起始IP地址 | 3字节指向地址的偏移量 |其中,起始IP地址和指向地址的偏移量都是无符号整数,采用小端字节序存储。
- 解析IP地址
要查询一个IP地址的归属地,需要先将IP地址转换成无符号整数,然后在IP数据库中查找对应的记录。具体步骤如下:
- 将IP地址转换成无符号整数,例如将
192.168.1.1转换成整数3232235777。 - 读取IP数据库文件头部的4个字节,得到IP数据库的起始IP地址和结束IP地址。
- 使用二分查找算法,在IP数据库中查找包含目标IP地址的记录。
- 读取记录中的指向地址的偏移量,根据偏移量读取指向地址的记录。
- 读取记录中的国家和地区信息,即为目标IP地址的归属地。
示例1:使用Python实现纯真IP数据库的查询功能。
import structdef ip2int(ip): return struct.unpack('!I', socket.inet_aton(ip))[0]def search_ip(ip): with open('QQWry.dat', 'rb') as f: start, end = struct.unpack('II', f.read(8)) ip = ip2int(ip) while start <= end: mid = (start + end) // 2 f.seek(mid * 7 + 4) mid_ip, offset = struct.unpack('I3xI', f.read(7)) if ip < mid_ip: end = mid - 1 elif ip > mid_ip: start = mid + 1 else: f.seek(offset + 4) data = [] c = f.read(1) while c != b'\x00': data.append(c) c = f.read(1) country = b''.join(data).decode('gbk') f.seek(offset + 5 + len(country)) data = [] c = f.read(1) while c != b'\x00': data.append(c) c = f.read(1) area = b''.join(data).decode('gbk') return country, area return None, Noneif __name__ == '__main__': country, area = search_ip('202.204.80.112') print(country, area)在上面的代码中,我们使用Python实现了纯真IP数据库的查询功能。首先,我们定义了一个ip2int()函数,用于将IP地址转换成无符号整数。然后,我们打开IP数据库文件,读取文件头部的4个字节,得到IP数据库的起始IP地址和结束IP地址。接着,我们使用二分查找算法,在IP数据库中查找包含目标IP地址的记录。如果找到了目标IP地址的记录,我们就读取记录中的国家和地区信息,即为目标IP地址的归属地。
示例2:使用C语言实现纯真IP数据库的查询功能。
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdint.h>#include <arpa/inet.h>typedef struct { uint32_t start_ip; uint32_t end_ip; uint32_t offset;} Record;uint32_t ip2int(char *ip) { struct in_addr addr; inet_aton(ip, &addr); return ntohl(addr.s_addr);}void search_ip(char *ip, char *filename) { FILE *fp = fopen(filename, "rb"); if (fp == NULL) { printf("Failed to open file %s\n", filename); return; } uint32_t start, end; fread(&start, sizeof(uint32_t), 1, fp); fread(&end, sizeof(uint32_t), 1, fp); uint32_t target_ip = ip2int(ip); while (start <= end) { uint32_t mid = (start + end) / 2; fseek(fp, mid * sizeof(Record) + 8, SEEK_SET); Record record; fread(&record, sizeof(Record), 1, fp); if (target_ip < record.start_ip) { end = mid - 1; } else if (target_ip > record.end_ip) { start = mid + 1; } else { fseek(fp, record.offset + 4, SEEK_SET); char buf[256]; fread(buf, 1, 256, fp); char *country = buf; char *area = strchr(country, '\0') + 1; printf("%s %s\n", country, area); return; } } printf("Not found\n"); fclose(fp);}int main(int argc, char *argv[]) { if (argc != 3) { printf("Usage: %s <ip> <filename>\n", argv[0]); return 1; } search_ip(argv[1], argv[2]); return 0;}在上面的代码中,我们使用C语言实现了纯真IP数据库的查询功能。首先,我们定义了一个ip2int()函数,用于将IP地址转换成无符号整数。然后,我们打开IP数据库文件,读取文件头部的4个字节,得到IP数据库的起始IP地址和结束IP地址。接着,我们使用二分查找算法,在IP数据库中查找包含目标IP地址的记录。如果找到了目标IP地址的记录,我们就读取记录中的国家和地区信息,即为目标IP地址的归属地。