zoukankan      html  css  js  c++  java
  • 解析oui.txt文件,通过MAC前缀获取Organization

    1、前言

      OUI是指Organizationally unique identifier  (组织唯一标识符),签发给各类组织的唯一标识符。MAC地址共有6个字节48位组成,前3个字节体现了OUI,其表明了NIC的制造组织。通常情况下,该标识符是唯一的。详细介绍参考:http://standards.ieee.org/develop/regauth/oui/public.html。oui.txt文件中记录世界所有网卡的制造厂商,共有18859个。文件中记录mac的前三位与公司的对应关系。本文目地是对oui.txt文件进行解析,生产一个信息的文件,在程序中可以根据制定的mac地址,快速查找其对应的公司名称。在此将MAC前三个字节简称为MAC前缀。

    2、初步处理

      oui.txt文件内容很有规律,根据MAC前缀由小到大记录。但是,MAC前缀并不是连续的,中间有些间断,但是顺序是由小到大。原始文件内容格式如下所示:

     OUI                Organization
     company_id            Organization
                      Address
      
      
     00-00-00   (hex)        XEROX CORPORATION
     000000     (base 16)        XEROX CORPORATION
                      M/S 105-50C
                    800 PHILLIPS ROAD
                    WEBSTER NY 14580
                    UNITED STATES
    
     00-00-01   (hex)        XEROX CORPORATION
     000001     (base 16)        XEROX CORPORATION
                      ZEROX SYSTEMS INSTITUTE
                    M/S 105-50C 800 PHILLIPS ROAD
                    WEBSTER NY 14580
                    UNITED STATES
    
     00-00-02   (hex)        XEROX CORPORATION
     000002     (base 16)        XEROX CORPORATION
                      XEROX SYSTEMS INSTITUTE
                    M/S 105-50C 800 PHILLIPS ROAD
                    WEBSTER NY 14580
                    UNITED STATES

      文件中网卡前缀00-00-00和000000两种形式,为了具备一致性,可以提前像00-00-00 (hex) XEROX CORPORATION的行。linux采用cat命令提取。

    命令为:cat oui.txt | grep hex > mac_hex_org.txt

    生成的mac_hex_org.txt文件内容如下:

     00-00-00   (hex)        XEROX CORPORATION
     00-00-01   (hex)        XEROX CORPORATION
     00-00-02   (hex)        XEROX CORPORATION
     00-00-03   (hex)        XEROX CORPORATION
     00-00-04   (hex)        XEROX CORPORATION
     00-00-05   (hex)        XEROX CORPORATION
     00-00-06   (hex)        XEROX CORPORATION

    更进一步抽取mac和org信息,可以对mac_hex_org.txt文件进行提前,采用一个简单的shell脚本,提前mac列和org列,分别保存在MAC.log和ORG.log文件中。shell脚本mac_org.sh如下:

    1 #!/bin/sh
    2 SRC_FILE=mac_hex_org.txt
    3 MAC_FILE=MAC.log
    4 ORG_FILE=ORG.log
    5 cat ${SRC_FILE} |grep -v "^#" | while read line;
    6 do
    7     echo "${line:0:8}" >> ${MAC_FILE}
    8     echo "${line:18}">>${ORG_FILE}
    9 done

    执行mac_org.sh生产MAC.log和ORG.log文件。两个文件的每行对应关系就是mac前缀与公司名称的关系。文件内容如下所示:

    00-00-00
    00-00-01
    00-00-02
    00-00-03
    00-00-04
    00-00-05
    00-00-06
    XEROX CORPORATION
    XEROX CORPORATION
    XEROX CORPORATION
    XEROX CORPORATION
    XEROX CORPORATION
    XEROX CORPORATION
    XEROX CORPORATION
    XEROX CORPORATION
    XEROX CORPORATION
    XEROX CORPORATION
    OMRON TATEISI ELECTRONICS CO.
    MATRIX CORPORATION
    CISCO SYSTEMS, INC.

    3、生产mac-org结构文件

      为了在程序快速查找,将MAC.log和ORG.log文件中对应关系转换为一个结构体,存入mac_org.log文件中。mac前缀是唯一的,对应转换为10进制的整数,相比字符串,查找更加方便。mac_org结构定义如下:

    //mac前缀和公司名称对应关系
    typedef struct mac_org { uint32_t key; //mac前缀作为key char org_name[ORG_NAME_LEN]; //公司名称 }mac_org;

      在程序中分别读取MAC.log和ORG.log的每一行,转换为一个mac_log结构,写入mac_log.log文件。转换程序如下所示:

      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <inttypes.h>
      4 #include <string.h>
      5 #include <time.h>
      6 #include <errno.h>
      7 #include <unistd.h>
      8 
      9 #define MAC_PREFIX_LEN           10          //mac前缀长度
     10 #define ORG_NAME_LEN              96           //公司名称长度
     11 #define MAC_LOG_FILE            "MAC.log"        //mac前缀文件
     12 #define ORG_LOG_FILE            "ORG.log"        //公司名称文件
     13 #define MAC_ORG_FILE            "mac2org.log"    //mac前缀对应公司名称文件
     14 
     15 #define PRINT_ERROR_POS()  do{                        
     16     printf("File: "__FILE__", Line:%d
    ",  __LINE__); 
     17 }while(0);
     18 
     19 //mac前缀和公司名称对应关系
     20 typedef struct mac_org
     21 {
     22     uint32_t key;   //mac前缀作为key
     23     char org_name[ORG_NAME_LEN]; //公司名称
     24 }mac_org;
     25 
     26 void print_mac_org(const mac_org *macorg)
     27 {
     28     printf("mac key:%d,org_name:%s
    ",macorg->key, macorg->org_name);
     29 }
     30 
     31 //将mac前缀转换为数字,前缀格式为:00-00-00
     32 uint32_t  macprefix2uint(const char *mac_prefix)
     33 {
     34     char mac[8] = {0};
     35     sscanf(mac_prefix, "%c%c-%c%c-%c%c",&mac[0],&mac[1],&mac[2],
     36         &mac[3],&mac[4],&mac[5]);
     37     return  strtoul(mac,0,16);
     38 }
     39 //将mac前缀文件和org文件组织成mac_org结构,并将结果存入文件
     40 int store_mac_org()
     41 {
     42     FILE *mac_fp = NULL;
     43     FILE *org_fp = NULL;
     44     FILE *fp = NULL;
     45     char mac_buf[MAC_PREFIX_LEN] = {0};
     46     char org_buf[ORG_NAME_LEN] = {0};
     47     uint32_t mac_len;
     48     uint32_t org_len;
     49     mac_org tmp;
     50 
     51     memset(&tmp, 0, sizeof(mac_org));
     52     if ((mac_fp = fopen(MAC_LOG_FILE, "r"))  == NULL)
     53     {
     54     fprintf(stderr,"Failed open mac log file: %s,errno: %u,reason: %s
    ",
     55         MAC_LOG_FILE, errno, strerror(errno));
     56     PRINT_ERROR_POS();
     57     return -1;
     58     }
     59     if ((org_fp = fopen(ORG_LOG_FILE, "r")) == NULL)
     60     {
     61     fprintf(stderr,"Failed open mac log file: %s,errno: %u,reason: %s
    ",
     62         ORG_LOG_FILE, errno, strerror(errno));
     63     PRINT_ERROR_POS();
     64     return -1;
     65     }
     66     if  ((fp = fopen(MAC_ORG_FILE, "wb")) == NULL)
     67     {
     68     fprintf(stderr,"Failed open mac log file: %s,errno: %u,reason: %s
    ",
     69         MAC_ORG_FILE, errno, strerror(errno));
     70     PRINT_ERROR_POS();
     71     return -1;
     72     }
     73     while(fgets(mac_buf, MAC_PREFIX_LEN, mac_fp) != NULL && 
     74         fgets(org_buf, ORG_NAME_LEN, org_fp) != NULL)
     75     {
     76     //去掉换行符'
    '
     77     mac_len = strlen(mac_buf);
     78     org_len = strlen(org_buf);
     79     if (mac_buf[mac_len-1] == '
    ')
     80     {
     81         mac_buf[mac_len-1] = 0;
     82     }
     83     if (org_buf[org_len-1] == '
    ')
     84     {
     85         org_buf[org_len-1] = 0;
     86     }
     87     //设置记录值
     88     tmp.key = macprefix2uint(mac_buf);
     89     strcpy(tmp.org_name,org_buf);
     90     //将该记录写入文件
     91     if(fwrite((void *)&tmp, sizeof(mac_org), 1, fp) == 0) 
     92     {
     93         fprintf(stderr, "Failed to write macorg to %s,errno:%u,reason:%s
    ",
     94             MAC_ORG_FILE, errno, strerror(errno));
     95         PRINT_ERROR_POS();
     96         return -1;
     97     }
     98     }
     99     fclose(mac_fp);
    100     fclose(org_fp);
    101     fclose(fp);
    102     return 0;
    103 }
    104 
    105 //mac前缀格式是00-00-00
    106 int main()
    107 {
    108     //判断文件是否存在
    109     if(access(MAC_ORG_FILE, F_OK) != 0)
    110     {
    111     if (store_mac_org() == -1)
    112     {
    113         fprintf(stderr, "Failed to create mac2org file.
    ");
    114         return -1;
    115     }
    116     else
    117     {
    118         printf("Successed to create mac2org file.
    ");
    119     }
    120     }
    121     return 0;
    122 }    

    执行程序:

    查看mac2org.log文件大小和内容如下:文件是二进制形式存入。

    4、根据mac前缀在mac2org.log查找org

      mac2org.log文件结构很明确,而且文件大小仅为1.8MB,完全可以将文件内容全部读到内存进行查找。而且mac2org.log记录是根据mac前缀有小到大的,即读到内存中的buffer中,mac_org记录是有序的,可以采用折半查找进行,以mac前缀转换的整数为key。查找程序如下所示:

      1 /**根据mac前缀(形如00-00-00)查找organzation
      2 先将mac_org.log读取到内存,然后进行折半查找
      3 @auther: Anker @date:2013-12-18
      4 **/
      5 #include <stdio.h>
      6 #include <stdlib.h>
      7 #include <inttypes.h>
      8 #include <string.h>
      9 #include <time.h>
     10 #include <errno.h>
     11 #include <unistd.h>
     12 
     13 #define MAC_PREFIX_LEN             10          //mac前缀长度
     14 #define ORG_NAME_LEN              96           //公司名称长度
     15 #define MAC_TYPE_COUNT            18860              //记录个数
     16 #define MAC_ORG_FILE            "mac2org.log"    //mac前缀对应公司名称文件
     17 
     18 #define PRINT_ERROR_POS()  do{                        
     19     printf("File: "__FILE__", Line:%d
    ",  __LINE__); 
     20 }while(0);
     21 
     22 //mac前缀和公司名称对应关系
     23 typedef struct mac_org
     24 {
     25     uint32_t key;   //mac前缀作为key
     26     char org_name[ORG_NAME_LEN]; //公司名称
     27 }mac_org;
     28 
     29 void print_mac_org(const mac_org *macorg)
     30 {
     31     printf("mac key:%d,org_name:%s
    ",macorg->key, macorg->org_name);
     32 }
     33 
     34 //将mac前缀转换为数字,前缀格式为:00-00-00
     35 uint32_t  macprefix2uint(const char *mac_prefix)
     36 {
     37     char mac[8] = {0};
     38     sscanf(mac_prefix, "%c%c-%c%c-%c%c",&mac[0],&mac[1],&mac[2],
     39         &mac[3],&mac[4],&mac[5]);
     40     return  strtoul(mac,0,16);
     41 }
     42 
     43 //二分查找过程
     44 int32_t binary_search(mac_org *macorg, int32_t n, uint32_t key)
     45 {
     46     //在有序表macorg[0..n-1]中进行二分查找,成功时返回结点的位置,失败时返回-1
     47     int32_t low = 0, high = n-1, mid; //置当前查找区间上、下界的初值
     48     if(macorg[low].key == key)
     49     {
     50       return low;
     51     }
     52     if(macorg[high].key == key)
     53     {
     54       return high;
     55     }
     56     while(low <= high)
     57     {
     58       //当前查找区间macorg[low..high]非空
     59       mid = low + ((high - low) / 2);
     60       //使用 (low + high) / 2 会有整数溢出的问题
     61       //(问题会出现在当low + high的结果大于表达式结果类型所能表示的最大值时,
     62       //这样,产生溢出后再/2是不会产生正确结果的,而low+((high-low)/2)不存在这个问题
     63       if(macorg[mid].key == key)
     64       {
     65           return mid; //查找成功返回
     66       }
     67       if(macorg[mid].key > key)
     68       {
     69           high = mid - 1; //继续在macorg[low..mid-1]中查找
     70      }
     71       else
     72       {
     73           low = mid + 1; //继续在macorg[mid+1..high]中查找
     74       }
     75     }
     76     return -1; //当low>high时表示查找区间为空,查找失败
     77 }//BinSeareh
     78 
     79 //给定一个mac前缀,获取对应的公司名称
     80 int get_org_by_mac(const char *mac_prefix, mac_org **rmg)
     81 {
     82     mac_org buffer[MAC_TYPE_COUNT];
     83     size_t read_num;
     84     uint32_t key = macprefix2uint(mac_prefix);
     85     int pos = -1;
     86     FILE *fp;
     87     if((fp = fopen(MAC_ORG_FILE, "rb")) == NULL)
     88     {
     89     fprintf(stderr, "Failed to open mac log file: %s,errno:%u,reason:%s
    ",
     90         MAC_ORG_FILE, errno, strerror(errno));
     91     PRINT_ERROR_POS();
     92     goto FAILED;
     93     }
     94     fflush(stdin);
     95     read_num = fread((void *)buffer, sizeof(mac_org), MAC_TYPE_COUNT, fp);
     96     if (read_num == 0 && errno != 0)
     97     {
     98     fprintf(stderr, "Failed to read mac log file: %s,errno:%u,reason:%s
    ",
     99         MAC_ORG_FILE, errno, strerror(errno));
    100     PRINT_ERROR_POS();
    101     goto FAILED;
    102     }
    103     pos = binary_search(buffer, read_num, key); 
    104     if (pos != -1)
    105     {
    106     *rmg = (mac_org *)malloc(sizeof(mac_org));
    107     if (rmg == NULL)
    108     {
    109         fprintf(stderr, "Failed to malloc memory,errno:%u,reason:%s
    ",
    110             errno, strerror(errno));
    111         PRINT_ERROR_POS();
    112         goto FAILED;
    113     }
    114     memset(*rmg, 0, sizeof(mac_org));
    115     memcpy(*rmg, &buffer[pos], sizeof(mac_org));
    116     }
    117     fclose(fp);
    118     return 0;
    119 FAILED:
    120     if(fp)
    121     {
    122       fclose(fp);
    123     }
    124     return -1;
    125 }
    126 
    127 //mac前缀格式是00-00-00
    128 int main(int argc,char **argv)
    129 {
    130     time_t time1,time2;
    131     time(&time1);
    132     mac_org *pmacorg = NULL;
    133     char *mac_prefix = NULL;
    134     if (argc != 2)
    135     {
    136       fprintf(stderr,"Paramer error,please input mac prefix.
    ");
    137       return -1;
    138     }
    139     if(access(MAC_ORG_FILE, F_OK) != 0)
    140     {
    141       printf("Can not found  mac2org file:%s.
    ", MAC_ORG_FILE);
    142       return -1;
    143     }
    144     mac_prefix = argv[1];
    145     if (get_org_by_mac(mac_prefix, &pmacorg) == -1)
    146     {
    147       fprintf(stderr, "Failed to search mac.
    ");
    148       PRINT_ERROR_POS();
    149       return -1;
    150     }
    151     if (!pmacorg)
    152     {
    153       printf("Can not find the mac prefix:%s
    ", mac_prefix);
    154     }
    155     else
    156     {
    157       time(&time2);
    158       printf("Successed to find the mac info, cost time:%lds
    ", time2 - time1);
    159       print_mac_org(pmacorg);
    160       free(pmacorg);
    161     }
    162     return 0;
    163 }    

    测试结果如下所示:

    采用折半查找,针对18860条记录,查询时间不足1秒,非常之快。

    5、总结

         刚开始拿到oui.txt文件时,看了文件的格式和规律。当时没有检查,以为mac前缀是连续的,如是开始第一个想到用hash做,mac前缀作为key,value是mac-key在文件中的偏移量。因为hash是唯一的,转换为整数,不会有冲突。实现后发现生产的mac_org.log文件1.2G之大,文件中有很多空白地方,排查发现mac前缀并不是连续的,而且MAC前缀还存在重复。如下图所示:

      故不可以采用hash实现。最后还是采用将文件内容记载到内存处理。mac_log结构的占用100字节,18860条共计约1.8MB,如今内存都已GB计算,完全可以全部加载到内存进行二分查找。

    6、参考网址

    http://my.oschina.net/duangr/blog/183789

  • 相关阅读:
    JavaScript按纯数字排序
    用jQuery监听浏览器窗口的变化
    jquery-jtemplates.js模板应用
    art-template模板应用
    JavaScript判断当前手机是Android还是iOS系统
    JavaScript数组转字符串,字符串转数组
    JavaScript数字转字符串,字符串转数字
    Play framework 安装
    JQuery判断数组中是否包含某个字符串
    js获取页面宽度高度及屏幕分辨率
  • 原文地址:https://www.cnblogs.com/Anker/p/3486344.html
Copyright © 2011-2022 走看看