以下是我的实现:使用的时候很简单: 点击(此处)折叠或打开 /** *1.调用qqwry_init_parser创建一个qqwry_parser_t类型的解析器 *2.初始化一个存放查询结果信息的qqwry_record *3.调用qqwry_querey_iprecord查询指定ip的归属地 *4.调用qqwry_release_parser释放资源 **/ qqwry_parser_t parser = qqwry_init_parser("/root/QQWry.Dat", VERBOSE_ENABLE, CACHE_ENABLE, 1); qqwry_record qr = QQWARY_RECORD_INITIALIZER(); qqwry_querey_iprecord(parser, "61.172.201.195", &qr); qqwry_release_parser(parser); 这是一个初级版本,还没有经过大量的测试,可能存在很多不完备的地方,希望亲们试用了之后,能够提出改进意见啊。 qqwry_utils.h 点击(此处)折叠或打开 /* * qqwry_utils.h * * Created on: 2012-4-26 * Author: zhanlin */ #ifndef QQWRY_UTILS_H_ #define QQWRY_UTILS_H_ int ipaddr_to_bytes(const char *src, char *dest); void bytes_to_ipaddr(const char *src, char *dest); inline int32_t char3_to_int32(const char *buf); #endif /* QQWRY_UTILS_H_ */ qqwry_utils.c 点击(此处)折叠或打开 /* * qqwry_utils.c * * Created on: 2012-4-26 * Author: zhanlin */ #include <string.h> #include <sys/types.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include "qqwry_utils.h" int ipaddr_to_bytes(const char *src, char *dest) { int n; char *newstr; char *sub; int i = 0; n = strlen(src); newstr = (char *) malloc(n + 1); if (newstr == NULL) { return -1; } memcpy(newstr, src, n); *(newstr + n) = 0; sub = strtok(newstr, "."); while (sub != NULL) { // printf("%s atoi %d\n", sub, atoi(sub)); *(dest + i) = (char) atoi(sub); sub = strtok(NULL, "."); i++; } free(newstr); return 0; } void bytes_to_ipaddr(const char *src, char *dest) { sprintf(dest, "%c.%c.%c.%c", src[0], src[1], src[2], src[3]); } inline int32_t char3_to_int32(const char *buf) { int32_t i = 0; memcpy(&i, buf, 3); return i; } qqwry_types.h 点击(此处)折叠或打开 /* * qqwry_types.h * * Created on: 2012-4-26 * Author: zhanlin */ #ifndef QQWRY_TYPES_H_ #define QQWRY_TYPES_H_ #include <sys/types.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <dirent.h> #pragma pack(0) typedef struct _qqwry_header { u_int32_t qh_idx_start; u_int32_t qh_idx_end; } qqwry_header, *qqwry_header_t; #endif /* QQWRY_TYPES_H_ */ qqwry_parser.h 点击(此处)折叠或打开 /* * qqwry_parser.h * * Created on: 2012-4-26 * Author: zhanlin */ #ifndef QQWRY_PARSER_H_ #define QQWRY_PARSER_H_ #include <sys/types.h> enum { VERBOSE_DISABLE = 0, VERBOSE_ENABLE = 1 }; enum { CACHE_DISABLE = 0, CACHE_ENABLE = 1 }; typedef struct _qqwry_record { char qr_ipaddr[20]; int32_t qr_ip; char qr_bigzone[1024]; char qr_smallzone[1024]; } qqwry_record, *qqwry_record_t; #define QQWARY_RECORD_INITIALIZER() {\ .qr_ipaddr = {0}, \ .qr_ip = 0, \ .qr_bigzone = {0}, \ .qr_smallzone = {0}, \ } struct _qqwry_parser; typedef struct _qqwry_parser qqwry_parser, *qqwry_parser_t; qqwry_parser_t qqwry_init_parser(const char *dbpath, int verb, int cache, int loaddb); int qqwry_load_db(qqwry_parser_t parser); void qqwry_unload_db(qqwry_parser_t parser); int qqwry_querey_iprecord(qqwry_parser_t parser, const char *ipaddr, qqwry_record_t qr); void qqwry_release_parser(qqwry_parser_t parser); int load_db_to_mem(qqwry_parser_t parser); #endif /* QQWRY_PARSER_H_ */ qqwry_types.c 点击(此处)折叠或打开 /* * qqwry_types.c * * Created on: 2012-4-26 * Author: root */ #include "qqwry_parser.h" #include "qqwry_utils.h" #include "qqwry_types.h" #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <iconv.h> #include <arpa/inet.h> #define trace(parser, fmt, …) {\ if((parser)->verbose) {\ printf(fmt, ##);\ }\ } struct _qqwry_parser { char qp_db_path[PATH_MAX]; int qp_db_fd; int qp_verbose; int qp_cache; int qp_errno; char *qp_memaddr; u_int32_t qp_foff; u_int32_t qp_fsize; qqwry_header_t qp_header; iconv_t qp_cd; }; /* int load_db_to_mem(qqwry_parser_t parser); void unload_db(qqwry_parser_t parser);*/ int qqwry_load_db(qqwry_parser_t parser) { struct stat buf; int retval = 0; parser->qp_errno = 0; // if ((retval = fstat(parser->qp_db_fd, &buf)) != 0) { parser->qp_errno = errno; if (parser->qp_verbose) perror("fstat execute failed"); return retval; } // parser->qp_fsize = buf.st_size; parser->qp_memaddr = (char *) malloc(buf.st_size); if (parser->qp_memaddr == NULL) { parser->qp_errno = errno; if (parser->qp_verbose) perror("malloc execute failed"); return -1; } // if ((retval = read(parser->qp_db_fd, parser->qp_memaddr, buf.st_size)) != buf.st_size) { parser->qp_errno = errno; if (parser->qp_verbose) perror("read file failed"); } parser->qp_header = (qqwry_header_t) parser->qp_memaddr; // parser->qp_cd = iconv_open("UTF-8", "GBK"); return 0; } void qqwry_unload_db(qqwry_parser_t parser) { if (parser->qp_memaddr) { free(parser->qp_memaddr); parser->qp_memaddr = NULL; } if (parser->qp_cd) { iconv_close(parser->qp_cd); } } int qqwry_open_db(qqwry_parser_t parser) { parser->qp_db_fd = open(parser->qp_db_path, O_RDONLY, 0777); parser->qp_errno = errno; if (parser->qp_verbose && parser->qp_db_fd < 0) perror("open qqwry datafile failed"); return parser->qp_db_fd; } void qqwry_close_db(qqwry_parser_t parser) { if (parser->qp_db_fd >= 0) { close(parser->qp_db_fd); parser->qp_db_fd = -1; } } int qqwry_read(qqwry_parser_t p, void *buf, int n) { if (p->qp_fsize < p->qp_foff + n) { n = p->qp_fsize - p->qp_foff; } memcpy(buf, (p->qp_memaddr + p->qp_foff), n); p->qp_foff += n; return n; } int qqwry_seek(qqwry_parser_t p, int32_t off) { if (p->qp_fsize < off) { return -1; } return (p->qp_foff = off); } int32_t qqwry_read3c_to_int32(qqwry_parser_t p) { char b3[3] = { 0 }; int32_t ret = 0; if (qqwry_read(p, b3, 3) != 3) { return -1; } ret |= (b3[0] & 0xFF); ret |= ((b3[1] 《 8) & 0xFF00); ret |= ((b3[2] 《 16) & 0xFF0000); return ret; } char qqwry_readc(qqwry_parser_t p) { char b[1] = { 0 }; if (qqwry_read(p, b, 1) != 1) { return -1; } return b[0];
} int qqwry_read_ip(qqwry_parser_t p, int32_t offset, int32_t *ip) { int ret = 0; ret = qqwry_seek(p, offset); if (ret < 0) return ret; ret = qqwry_read(p, ip, 4); *ip = ntohl(*ip); return ret; } /** * 把两个byte当作无符号数进行比较 * * @param b1 * @param b2 * @return 若b1大于b2则返回1,相等返回0,小于返回-1 */ int qqwry_compare_char(char c1, char c2) { if ((c1 & 0xFF) > (c2 & 0xFF)) // 比较是否大于 return 1; else if ((c1 ^ c2) == 0) // 判断是否相等 return 0; else return -1; } /** * 把类成员ip和beginIp比较,注意这个beginIp是big-endian的 * * @param ip * 要查询的IP * @param beginIp * 和被查询IP相比较的IP * @return 相等返回0,ip大于beginIp则返回1,小于返回-1。 */ inline int qqwry_compare_ip(int32_t *ip, int32_t *beginip) { char *ipc = (char *) ip; char *beginipc = (char *) beginip; int i = 0; for (; i < 4; i++) { int r = qqwry_compare_char((*(ipc + i)), *(beginipc + i)); if (r != 0) return r; } return 0; } qqwry_parser_t qqwry_init_parser(const char *dbpath, int verb, int cache, int loaddb) { qqwry_parser_t qp = (qqwry_parser_t) malloc(sizeof(qqwry_parser)); if (qp) { // qp->qp_cache = cache; qp->qp_errno = 0; qp->qp_db_fd = -1; qp->qp_verbose = verb; qp->qp_memaddr = NULL; qp->qp_foff = 0; qp->qp_header = NULL; strncpy(qp->qp_db_path, dbpath, PATH_MAX); // if (loaddb) { if (qqwry_open_db(qp) >= 0) { if (qqwry_load_db(qp) != 0) qp->qp_errno = errno; else qqwry_close_db(qp); } else { qp->qp_errno = errno; } } } return qp; } int32_t get_middle_offset(int32_t begin, int32_t end) { #define IP_RECORD_LENGTH 7 long records = (end - begin) / IP_RECORD_LENGTH; records 》= 1; if (records == 0) records = 1; return begin + records * IP_RECORD_LENGTH; } int32_t qqwry_locate_ip(qqwry_parser_t p, const char *ipaddr) { int32_t ip = 0; int32_t rip; int ret = 0; int32_t m; int32_t i = p->qp_header->qh_idx_start; int j = p->qp_header->qh_idx_end; ip = (int32_t) inet_addr(ipaddr) ; // ipaddr_to_bytes(ipaddr, (char *) &ip); qqwry_read_ip(p, p->qp_header->qh_idx_start, &rip); ret = qqwry_compare_ip(&ip, &rip); if (ret == 0) return p->qp_header->qh_idx_start; else if (ret < 0) return -1; // 开始二分搜索 for (; i < j;) { m = get_middle_offset(i, j); qqwry_read_ip(p, m, &rip); ret = qqwry_compare_ip(&ip, &rip); // log.debug(Utils.getIpStringFromBytes(b)); if (ret > 0) i = m; else if (ret < 0) { if (m == j) { j -= IP_RECORD_LENGTH; m = j; } else { j = m; } } else { qqwry_seek(p, m + 4); return qqwry_read3c_to_int32(p); }
} // 如果循环结束了,那么i和j必定是相等的,这个记录为最可能的记录,但是并非 // 肯定就是,还要检查一下,如果是,就返回结束地址区的绝对偏移 qqwry_seek(p, m + 4); m = qqwry_read3c_to_int32(p); qqwry_read_ip(p, m, &rip); ret = qqwry_compare_ip(&ip, &rip); if (ret <= 0) return m; else return -1; } size_t conver_gbk_to_utf8(qqwry_parser_t p, char *inbuf, char *outbuf) { int n = strlen(inbuf); char *in = inbuf; char *out = outbuf; size_t outlen = n * 4; iconv(p->qp_cd, &in, (size_t *) &n, &out, &outlen); outlen = strlen(outbuf); return outlen; } void qqwry_read_string(qqwry_parser_t p, char *buf) { int i = 0; char tmp[512] = { 0 }; for (i = 0, tmp[i] = qqwry_readc(p); tmp[i] != 0; tmp[++i] = qqwry_readc(p)) ; conver_gbk_to_utf8(p, tmp, buf); } void qqwry_read_smallzone(qqwry_parser_t p, char *buf) { char flag = qqwry_readc(p); if (flag == 0x01 || flag == 0x02) { long areaOffset = qqwry_read3c_to_int32(p); if (areaOffset == 0) p->qp_errno = 0; else { qqwry_seek(p, areaOffset); qqwry_read_string(p, buf); } } else { return qqwry_read_string(p, buf); } } int qqwry_querey_iprecord(qqwry_parser_t parser, const char *ipaddr, qqwry_record_t qr) { #define AREA_FOLLOWED 0x1 #define NO_AREA 0x2 int32_t offset = qqwry_locate_ip(parser, ipaddr); char flag = 0; printf("ip off: %d\n", offset); qqwry_seek(parser, offset + 4); // 读取第一个字节判断是否标志字节 flag = qqwry_readc(parser); if (flag == AREA_FOLLOWED) { // 读取国家偏移 int32_t country_offset = qqwry_read3c_to_int32(parser); // 跳转至偏移处 qqwry_seek(parser, country_offset); // 再检查一次标志字节,因为这个时候这个地方仍然可能是个重定向 flag = qqwry_readc(parser); if (flag == NO_AREA) { qqwry_seek(parser, qqwry_read3c_to_int32(parser)); qqwry_read_string(parser, qr->qr_bigzone); qqwry_seek(parser, country_offset + 4); } else { qqwry_seek(parser, country_offset); qqwry_read_string(parser, qr->qr_bigzone); } // 读取地区标志 qqwry_read_smallzone(parser, qr->qr_smallzone); } else if (flag == NO_AREA) { int32_t country_offset = qqwry_read3c_to_int32(parser); qqwry_seek(parser, country_offset); qqwry_read_string(parser, qr->qr_bigzone); qqwry_seek(parser, offset + 8); qqwry_read_string(parser, qr->qr_smallzone); } else { qqwry_seek(parser, parser->qp_foff - 1); qqwry_read_string(parser, qr->qr_bigzone); qqwry_read_string(parser, qr->qr_smallzone); } return 0; } void qqwry_release_parser(qqwry_parser_t parser) { if (parser != NULL) { // if (parser->qp_memaddr) { qqwry_unload_db(parser); } // free(parser); parser = NULL; } } ipinfo.c 点击(此处)折叠或打开 /* ============================================================================ Name : ipinfo.c Author : ZhanLin Version : Copyright : GPL v2 Ansi-style ============================================================================ */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "qqwry_parser.h" #include <iconv.h> int main(void) { qqwry_parser_t parser = qqwry_init_parser("/root/QQWry.Dat", VERBOSE_ENABLE, CACHE_ENABLE, 1); qqwry_record qr = QQWARY_RECORD_INITIALIZER(); qqwry_querey_iprecord(parser, "61.172.201.195", &qr); qqwry_release_parser(parser); printf("big zone: %s, small zone: %s\n", qr.qr_bigzone, qr.qr_smallzone); return EXIT_SUCCESS; } (责任编辑:IT) |