• 14海量日志提取出现次数最多的IP


        问题描述:现有某网站海量日志数据,提取出某日访问该网站次数最多的那个IP。

     

        分析:IP地址是32位的二进制数,所以共有N=2^32=4G个不同的IP地址, 如果将每个IP地址看做是数组的索引的话,那么需要创建一个unsigned count[N]的数组,即可统计出每个IP的访问次数,但是这个数组的大小是4G*4=16G, 远远超过了32位计算机所支持的内存大小,因此不能直接创建这个数组。

        采用划分法解决这个问题,假设允许使用的内存是512M,512M内存可以统计128M个不同的IP地址的访问次数。而4G/128M = 32,所以只要把IP地址划分成32个不同的区间,分别统计出每个区间中访问次数最大的IP,然后就可以计算出所有IP地址中访问次数最大的IP了。

        可以把IP地址的最高5位作为区间编号, 剩下的27位作为区间内的值,建立32个临时文件,代表32个区间,把相同区间的IP地址保存到同一的临时文件中。

        例如:ip=0x1f4e2342,高5位id=ip>>27=0x11=3,低27位是value=ip&0x07ffffff = 0x074e2342。所以,当扫描到IP为0x1f4e2342时,将value保存在tmp3文件中。

        按照上面的方法扫描海量日志,可以得到32个临时文件,每个临时文件中的IP地址的取值范围属于[0-128M),因此可以统计出每个IP地址的访问次数。从而找到访问次数最大的IP地址。

     

    代码如下:

    #define  N  32                                                         //临时文件数 

    #define  ID(x) (x>>27)                                           //x对应的文件编号 

    #define  VALUE(x) (x&0x07ffffff)                          //x在文件中保存的值 

    #define  MAKE_IP(x,y)  ((x<<27)|y)            //由文件编号和值得到IP地址. 

    #define  MEM_SIZE 128*1024*1024                 

    char  * data_path = "D:/test/ip.dat";       //ip数据 

     

    //产生n个随机IP地址 

    void   make_data(const int& n)        

    //找到访问次数最大的ip地址 

    int main() 

        make_data(100000000);                                  //产生测试用的IP数据 

        fstream arr[N]; 

        for (int i=0; i<N; ++i)                                 //创建N个临时文件 

        { 

            char tmp_path[128];                      

           sprintf(tmp_path,"D:/test/tmp%d.dat",i); 

            arr[i].open(tmp_path,ios::trunc|ios::in|ios::out|ios::binary); //打开第i个文件 

            if( !arr[i]) 

            { 

                cout<<"openfile"<<i<<"error"<<endl; 

            } 

        } 

        ifstreaminfile(data_path,ios::in|ios::binary);  //读入测试用的IP数据 

        unsigned data; 

        while(infile.read((char*)(&data),sizeof(data))) 

        { 

            unsigned val=VALUE(data); 

            int key=ID(data); 

            arr[key].write((char*)(&val),sizeof(val));           //保存到临时文件件中 

        } 

     

        for(unsigned i=0; i<N; ++i) 

        { 

            arr[i].seekg(0); 

        } 

        unsigned  max_ip = 0;                    //出现次数最多的ip地址 

        unsigned  max_times = 0;             //最大只出现的次数 

        //统计每个数出现的次数 

        unsigned *count = newunsigned[MEM_SIZE];   

        for (unsigned i=0; i<N; ++i) 

        { 

            memset(count, 0,sizeof(unsigned)*MEM_SIZE); 

            //统计每个临时文件件中不同数字出现的次数 

            unsigned data; 

            while(arr[i].read((char*)(&data),sizeof(unsigned)))      

            { 

                ++count[data]; 

            }  

            //找出出现次数最多的IP地址 

            for(unsigned j=0; j<MEM_SIZE;++j)                            

            { 

                if(max_times<count[j])            

                { 

                    max_times = count[j]; 

                    max_ip = MAKE_IP(i,j);        // 恢复成原ip地址

                } 

            } 

        } 

        unsigned char *result=(unsigned char *)(&max_ip); 

        printf("出现次数最多的IP为:%d.%d.%d.%d,共出现%d次", result[0],result[1], result[2], result[3], max_times); 

     

    (http://blog.csdn.net/v_july_v/article/details/6712171)

  • 相关阅读:
    【译】常用网络端口号列表
    使用Simian进行重复代码检测
    使用GCOV进行代码覆盖率统计
    AFL Fuzz安装及完成一次简单的模糊测试
    数据可视化概述
    完成下方的 which_date() 函数,并返回某一起始时间后特定一段时间的日期
    linux用户不在sudoers文件中
    linux /lib64/libc.so.6: version `GLIBC_2.17′ not found
    web api 2.0 上传文件超过4M时,出现404错误
    Centos7 编译安装 Nginx Mariadb Asp.net Core2 (实测 笔记 Centos 7.7 + Openssl 1.1.1d + Mariadb 10.3.7 + Nginx 1.16.1 + Asp.net. Core 2 )
  • 原文地址:https://www.cnblogs.com/gqtcgq/p/7247173.html
Copyright © 2020-2023  润新知