1. 准备工作
- 数据库 : 解析 IP 地理位置的的数据库来自 GeoLite2 开源数据库: 。
- C 语言 API : 使用的 API 是 maxmind 官网的开源项目 libmaxminddb, 地址是 。
准备好这两个就可以了。
2. 敲代码
我使用的操作系统是 CentOS7.1。
2.1 编译 libmaxminddb
把 libmaxminddb 的代码下载下来,随便放在什么地方, 然后解压,进入解压后的目录,执行 bootstrap,configure,make$ tar xzf libmaxminddb-1.3.1.tar.gz$ cd libmaxminddb-1.3.1$ ./bootstrap$ ./configure$ make
1.在执行 bootstrap 的时候可能会报错,应该是缺少 autoconf 之类的自动构建工具导致的,到谷歌或者百度查询一下安装即可。
2.在执行 make 命令的时候,也会报错,不过报错信息指向的是 libmaxminddb-1.3.1/t 里面缺少 libtap/tap.h。 https://github.com/pozorvlak/libtap 是 libtap 在 GitHub 上的地址, 其项目首页上的注释是:Testing library for C, implementing the Test Anything Protocol. Written by Nik Clayton.
既然是测试使用的,那么不编译应该也没什么大问题。
3.看 make 命令后的编译记录,可以发现 libmaxminddb.a 静态链接库已经编译好了, 并且放在了 libmaxminddb-1.3.1/src/.libs 目录里面。
[root@fengbo libmaxminddb-1.3.1]# ls src/.libs/ -ltotal 312-rw-r--r--. 1 root root 12632 Dec 8 22:30 data-pool.o-rw-r--r--. 1 root root 111620 Dec 8 22:30 libmaxminddb.alrwxrwxrwx. 1 root root 18 Dec 8 22:30 libmaxminddb.la -> ../libmaxminddb.la-rw-r--r--. 1 root root 959 Dec 8 22:30 libmaxminddb.lailrwxrwxrwx. 1 root root 21 Dec 8 22:30 libmaxminddb.so -> libmaxminddb.so.0.0.7lrwxrwxrwx. 1 root root 21 Dec 8 22:30 libmaxminddb.so.0 -> libmaxminddb.so.0.0.7-rwxr-xr-x. 1 root root 79477 Dec 8 22:30 libmaxminddb.so.0.0.7-rw-r--r--. 1 root root 100104 Dec 8 22:30 maxminddb.o
2.2 编写示例代码
示例代码是从 maxmind 的官方 GitHub 上直接复制下来的。不过我加了几条日志信息。 https://github.com/maxmind/libmaxminddb/blob/master/doc/libmaxminddb.md#example
代码如下:$cat example.c
#include#include "maxminddb.h"#include #include #define xdebug(fmt, arg...) \ do{\ printf("%s %d : ", __FILE__, __LINE__); \ printf(fmt, ##arg); \ printf("\n"); \ }while(0)int main(int argc, char **argv){ if(argc < 2) { xdebug("Usage : %s dbfilename IP", argv[0]); } char *filename = argv[1]; char *ip_address = argv[2]; MMDB_s mmdb; int status = MMDB_open(filename, MMDB_MODE_MMAP, &mmdb); if (MMDB_SUCCESS != status) { fprintf(stderr, "\n Can't open %s - %s\n", filename, MMDB_strerror(status)); if (MMDB_IO_ERROR == status) { fprintf(stderr, " IO error: %s\n", strerror(errno)); } exit(1); } int gai_error, mmdb_error; MMDB_lookup_result_s result = MMDB_lookup_string(&mmdb, ip_address, &gai_error, &mmdb_error); if (0 != gai_error) { fprintf(stderr, "\n Error from getaddrinfo for %s - %s\n\n", ip_address, gai_strerror(gai_error)); exit(2); } if (MMDB_SUCCESS != mmdb_error) { fprintf(stderr, "\n Got an error from libmaxminddb: %s\n\n", MMDB_strerror(mmdb_error)); exit(3); } MMDB_entry_data_list_s *entry_data_list = NULL; int exit_code = 0; if (result.found_entry) { int status = MMDB_get_entry_data_list(&result.entry, &entry_data_list); if (MMDB_SUCCESS != status) { fprintf( stderr, "Got an error looking up the entry data - %s\n", MMDB_strerror(status)); exit_code = 4; goto end; } if (NULL != entry_data_list) { MMDB_dump_entry_data_list(stdout, entry_data_list, 2); } } else { fprintf( stderr, "\n No entry for this IP address (%s) was found\n\n", ip_address); exit_code = 5; }end: MMDB_free_entry_data_list(entry_data_list); MMDB_close(&mmdb); exit(exit_code);}
编译我们的示例代码:
把 libmaxminddb 源码中的 libmaxminddb-1.3.1/include/maxminddb_config.h 和 libmaxminddb-1.3.1/include/maxminddb.h 放到 example.c 所在的目录下。 还有 libmaxminddb-1.3.1/src/.libs/libmaxminddb.a 也要放进来。
$ gcc -o example example.c ./libmaxminddb.a$ ls example example.c libmaxminddb.a maxminddb_config.h maxminddb.h
2.3 下载 GeoLite2 开源数据库
到网页 https://dev.maxmind.com/geoip/geoip2/geolite2/ 中,下载 GeoLite2 的数据库。Downloads
Database | binary, gzipped | , zipped |
---|---|---|
GeoLite2 City | (md5 checksum) | (md5 checksum) |
GeoLite2 Country | (md5 checksum) | (md5 checksum) |
GeoLite2 ASN () | (md5 checksum) | (md5 checksum) |
我下载的是 GeoLite2 City
数据库。解压后的文件如下:
[root@fengbo maxmind]# ls GeoLite2-City_20171205/COPYRIGHT.txt GeoLite2-City.mmdb LICENSE.txt README.txt
2.4 测试一下这个程序的效果
先拿到一个 IP,比如 www.fengbohello.top 的 IP。[root@fengbo maxmind]$ ping www.fengbohello.topPING www.fengbohello.top (139.199.212.133) 56(84) bytes of data.64 bytes from 139.199.212.133: icmp_seq=1 ttl=48 time=41.7 ms
运行一下 example 试试看:
[root@fengbo maxmind]$ ./example GeoLite2-City_20171205/GeoLite2-City.mmdb "139.199.212.133" { "city": { "geoname_id": 1816670"names": { "de": "Peking" "en": "Beijing" "es": "Pekín" "fr": "Pékin" "ja": "北京市" "pt-BR": "Pequim" "ru": "Пекин" "zh-CN": "北京" } } "continent": { "code": "AS" "geoname_id": 6255147 "names": { "de": "Asien" "en": "Asia" "es": "Asia" "fr": "Asie" "ja": "アジア" "pt-BR": "Ásia" "ru": "Азия" "zh-CN": "亚洲" } } "country": { "geoname_id": 1814991 "iso_code": "CN" "names": { "de": "China" "en": "China" "es": "China" "fr": "Chine" "ja": "中国" "pt-BR": "China" "ru": "Китай" "zh-CN": "中国" } } "location": { "accuracy_radius": 50 "latitude": 39.928900 "longitude": 116.388300 "time_zone": "Asia/Shanghai" } "registered_country": { "geoname_id": 1814991 "iso_code": "CN" "names": { "de": "China" "en": "China" "es": "China" "fr": "Chine" "ja": "中国" "pt-BR": "China" "ru": "Китай" "zh-CN": "中国" } } "subdivisions": [ { "geoname_id": 2038349 "iso_code": "11" "names": { "en": "Beijing" "fr": "Municipalité de Pékin" "zh-CN": "北京市" } } ] }
我擦,解析结果居然是北京。我问了,他说我们的服务器是腾讯云的,当时选择的是深圳机房。
下面是使用不同的厂商得到的结果:
厂商 | 地理位置 |
---|---|
百度 | 广东省广州市 腾讯集团 |
ip.cn | 广东省深圳市 腾讯云 |
freegeoip.net | China.Beijing |
新浪:int.dpool.sina.com.cn | 中国.广东.广州 |
淘宝:ip.taobao.com | 中国.华南.广东省.广州市.电信 |
腾讯:ip.qq.com | 中国广东省广州市 未知 |
有意思吧,我也不知道该信谁的。
同步发表: