从纯真ip数据库读取ip地址对应的地理信息的程序

这次又贴一个小程序,是根据luma所写的关于纯真ip数据库格式说明文档而完成了。luma的文章链接地址为:
http://lumaqq.linuxsir.org/article/qqwry_format_detail.html
本代码借鉴了文中已经贴出的部分java代码的片段

本程序可以根据输入的ip地址,显示其对应的地理信息,信息来源于纯真ip数据库文件"QQWry.Dat",从网上所搜可以很容易下载到

/**
 * file: getipinfo.c
 * author: rare
 * date: 2008/12/02
 * email: dux003#163.com
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>

#define MAX_BUF_LEN 128

static void usage()
{
    printf("usage:/n");
    printf("/tgetipinfo xxx.xxx.xxx.xxx/n");
    exit(0);
}

static int readint3(FILE* fp)
{
    int val;
    unsigned char byte[3];

    fread(byte, 1, 3, fp);
    val = byte[0] & 0xFF;
    val |= (byte[1]<< 8) & 0xFF00;
    val |= (byte[2]<<16) & 0xFF0000;

    return val;
}

static void readstring(FILE* fp, char* strbuf, int* len)
{
    int i = 0;

    fread(&strbuf[i], 1, 1, fp);
    while (strbuf[i] != 0 && i<(*len)-1)
    {
        i++;
        fread(&strbuf[i], 1, 1, fp);
    }

    if (strbuf[i] != 0)
        strbuf[i] = 0;
    *len = i;
}

static int findrecoffset(FILE* fp, unsigned int ip)
{
    int first_index_pos, last_index_pos;
    unsigned int fip, lip, tip;
    int rec_pos;
    int tmp;

    //read first index item offset
    fread(&first_index_pos, 1, 4, fp);
    //read last index item offset
    fread(&last_index_pos, 1, 4, fp);

    while (first_index_pos+7 < last_index_pos)
    {
        fseek(fp, first_index_pos, SEEK_SET);
        fread(&fip, 1, 4, fp);
        fseek(fp, last_index_pos, SEEK_SET);
        fread(&lip, 1, 4, fp);
   
        if (ip > lip)
        {
            first_index_pos = last_index_pos;   //tricks to exit loop
            last_index_pos += 7;
        }
        else    //must be in range(fip, lip)
        {
            tmp = first_index_pos + (last_index_pos-first_index_pos)/14*7;
            fseek(fp, tmp, SEEK_SET);
            fread(&tip, 1, 4, fp);

            if (ip > tip)
                first_index_pos = tmp;
            else
                last_index_pos = tmp;
        }
    }


    fseek(fp, first_index_pos, SEEK_SET);
    fread(&fip, 1, 4, fp);
    rec_pos = readint3(fp);
    fseek(fp, rec_pos, SEEK_SET);
    fread(&lip, 1, 4, fp);

    if (ip<fip || ip>lip)
        return -1;

    return rec_pos;
}

static void readipinfo(FILE* fp, int offset)
{
    unsigned char mode;
    int rec_pos;

    int buflen;
    char country[MAX_BUF_LEN];
    char area[MAX_BUF_LEN];

    //read information from offset rec_pos
    fseek(fp, offset, SEEK_SET);
    fseek(fp, 4, SEEK_CUR);
    fread(&mode, 1, 1, fp);
    if (mode == 1)  //redirection mode 1
    {
        rec_pos = readint3(fp);

        fseek(fp, rec_pos, SEEK_SET);

        fread(&mode, 1, 1, fp);
        if (mode == 2)
        {
            rec_pos = readint3(fp);

            buflen = MAX_BUF_LEN;
            readstring(fp, area, &buflen);

            fseek(fp, rec_pos, SEEK_SET);
            buflen = MAX_BUF_LEN;
            readstring(fp, country, &buflen);

            printf("country:%s/n", (char*)country);
            printf("area:%s/n", (char*)area);
        }
        else
        {
            //move back one byte
            fseek(fp, -1, SEEK_CUR);

            buflen = MAX_BUF_LEN;
            readstring(fp, country, &buflen);
            buflen = MAX_BUF_LEN;
            readstring(fp, area, &buflen);

            printf("country:%s/n", (char*)country);
            printf("area:%s/n", (char*)area);
        }
    }
    else if (mode == 2) //redirection mode 2
    {
        rec_pos = readint3(fp);

        buflen = MAX_BUF_LEN;
        readstring(fp, area, &buflen);

        fseek(fp, rec_pos, SEEK_SET);
        buflen = MAX_BUF_LEN;
        readstring(fp, country, &buflen);

        printf("country:%s/n", (char*)country);
        printf("area:%s/n", (char*)area);
    }
    else    //no redirection
    {
        //move back one byte
        fseek(fp, -1, SEEK_CUR);

        buflen = MAX_BUF_LEN;
        readstring(fp, country, &buflen);
        buflen = MAX_BUF_LEN;
        readstring(fp, area, &buflen);

        printf("country:%s/n", (char*)country);
        printf("area:%s/n", (char*)area);
    }
}

static int getipinfo(in_addr_t ip)
{
    FILE* fp;
    unsigned int nip;
    int rec_pos;
    const unsigned int cnip = ntohl(ip);

    fp = fopen("QQWry.Dat", "rb");
    if (fp == NULL)
    {
        fprintf(stderr, "open ip database error!/n");
        return -1;
    }

    if ((rec_pos = findrecoffset(fp, cnip)) == -1)
    {
        fprintf(stderr, "can not find record of the ip address/n");
        fclose(fp);
        return -1;
    }

    readipinfo(fp, rec_pos);

    fclose(fp);
    return 0;
}

int main(int argc, char** argv)
{
    in_addr_t ip;

    //check input
    if (argc != 2)
        usage();

    ip = inet_addr(argv[1]);
    if (ip == 0xFFFFFFFF)
    {
        printf("invalid ip address/n");
        exit(1);
    }

    //get ip information
    getipinfo(ip);

    return 0;
}

//运行效果
rare@rare:~/mysrc/qqwry$ ./getipinfo 59.66.122.77
country:清华大学
area:26#楼

注意:运行程序的conosle编码格式必须设置为GBK,这是纯真ip数据库采用的编码格式,否则中文会显示为乱码
要读取纯真ip数据库版本信息,则执行 ./getipinfo 255.255.255.*
其中“*”为1至254都可。以下是我所采用的版本
rare@rare:~/mysrc/qqwry$ ./getipinfo 255.255.255.1
country:纯真网络
area:2008年11月30日IP数据

你可能感兴趣的:(数据库,File,database,input,byte,FP)