1.根据IP获取用户地理位置思路:
通过IP地址去查询数据库,然后从数据库里面提取相应地理位置信息
2.下载MaxMind的数据库下载地址
https://dev.maxmind.com/geoip/geoip2/geolite2/
它有 binary格式 和 CSV格式的,可以先都下载:
GeoLite2-City.mmdb.gz
GeoLite2-Country.mmdb.gz
GeoLite2-City-CSV_20180306.zip
GeoLite2-Country-CSV_20180306.zip
3.然后是操作它数据库的libmaxminddb的github地址:
https://github.com/maxmind/libmaxminddb/releases
libmaxminddb安装命令:
$ ./configure
$ make
$ make check
$ sudo make install
$ sudo ldconfig
libmaxminddb说明文档地址:
http://maxmind.github.io/libmaxminddb/
而且还给出一个例子:
#include
#include
#include
#include
int main(int argc, char **argv)
{
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);
}
命令如下:
./mmdb <dbpath> <IP>
./mmdb /home/share/GeoLite2-City.mmdb 112.225.35.70
效果如下:
{
"city":
{
"geoname_id":
1805753
"names":
{
"de":
"Jinan"
"en":
"Jinan"
"es":
"Jinan"
"fr":
"Jinan"
"ja":
"済南市"
"pt-BR":
"Jinan"
"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":
36.668300
"longitude":
116.997200
"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":
1796328
"iso_code":
"SD"
"names":
{
"en":
"Shandong"
"fr":
"Province de Shandong"
"zh-CN":
"山东省"
}
}
]
}
比如我只想获取国家,省份和城市我写的例子如下:
/*
* gcc -v test.c -o mmdb -lmaxminddb
*/
#include
#include
#include
#include
#include
#include "cJSON.h"
int main(int argc, char **argv)
{
char *filename = "GeoLite2-City.mmdb";
char *ip_address = argv[1];
MMDB_s mmdb;
char country[8] = {0};
char province[64] = {0};
char city[32] = {0};
if (argc < 2){
printf("usage \n" );
exit(1);
}
int status = MMDB_open(filename, MMDB_MODE_MMAP, &mmdb);
if (MMDB_SUCCESS != status){
printf("can't open %s - %s\n", filename, MMDB_strerror(status));
if ( MMDB_IO_ERROR == status ) {
printf(" 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) {
printf("Error from getaddrinfo for %s - %s\n\n",
ip_address, gai_strerror(gai_error));
exit(2);
}
if (MMDB_SUCCESS != mmdb_error) {
printf("Got an error from libmaxminddb: %s\n\n",
MMDB_strerror(mmdb_error));
exit(3);
}
MMDB_entry_data_s entry_data;
// get country
status = MMDB_get_value(&result.entry, &entry_data,
"country", "iso_code", NULL);
if ( ! entry_data.has_data ) {
printf("entry_data has no data\n");
goto end;
}
if ( entry_data.type != MMDB_DATA_TYPE_UTF8_STRING ) {
printf("entry_data's type isn't UTF-8");
goto end;
}
memcpy(country, entry_data.utf8_string, entry_data.data_size);
printf("country:%s\n", country);
// get province
status = MMDB_get_value(&result.entry, &entry_data,
"subdivisions", "0", "names", "en", NULL);
if ( ! entry_data.has_data ) {
printf("entry_data has no data\n");
goto end;
}
if ( entry_data.type != MMDB_DATA_TYPE_UTF8_STRING ) {
printf("entry_data's type isn't UTF-8");
goto end;
}
memcpy(province, entry_data.utf8_string, entry_data.data_size);
printf("province:%s\n", province);
// get city
status = MMDB_get_value(&result.entry, &entry_data,
"city", "names", "en", NULL);
if ( ! entry_data.has_data ) {
printf("entry_data has no data\n");
goto end;
}
if ( entry_data.type != MMDB_DATA_TYPE_UTF8_STRING ) {
printf("entry_data's type isn't UTF-8");
goto end;
}
memcpy(city, entry_data.utf8_string, entry_data.data_size);
printf("city:%s\n", city);
end:
MMDB_close(&mmdb);
exit(0);
}