解析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\n",  __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\n",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\n",
 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\n",
 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\n",
 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     //去掉换行符'\n'
 77     mac_len = strlen(mac_buf);
 78     org_len = strlen(org_buf);
 79     if (mac_buf[mac_len-1] == '\n')
 80     {
 81         mac_buf[mac_len-1] = 0;
 82     }
 83     if (org_buf[org_len-1] == '\n')
 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\n",
 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.\n");
114         return -1;
115     }
116     else
117     {
118         printf("Successed to create mac2org file.\n");
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\n",  __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\n",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\n",
 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\n",
 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\n",
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.\n");
137       return -1;
138     }
139     if(access(MAC_ORG_FILE, F_OK) != 0)
140     {
141       printf("Can not found  mac2org file:%s.\n", 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.\n");
148       PRINT_ERROR_POS();
149       return -1;
150     }
151     if (!pmacorg)
152     {
153       printf("Can not find the mac prefix:%s\n", mac_prefix);
154     }
155     else
156     {
157       time(&time2);
158       printf("Successed to find the mac info, cost time:%lds\n", 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计算,完全可以全部加载到内存进行二分查找。

时间: 2024-10-31 06:58:33

解析oui.txt文件,通过MAC前缀获取Organization的相关文章

基于android中读取assets目录下a.txt文件并进行解析的深入分析

android读取assets文件下的内容,一般都是使用getAsset.open()方法,并将文件的路径作为参数传入,而当我们解析一个目录下的文件时需要对其进行解析时,比如:a.txt文件的内容为: name android,liu class 1,2,3,4 这些文件有时就像是数据库文件的格式一样,我们就需要对其进行解析. 我们知道获取assets文件后返回的是一个inputstream而不是一个file类型,所以我们需要对inputstream进行解析.主要分为两个阶段:第一个阶段为:去换

Mac打不开txt文件怎么办

  有时候,苹果电脑 Mac OS X 系统上双击 txt 文件(尤其是 PC 传过来的),会弹出「未能打开文稿XXX,编码"Unicode(UTF-8)不适用」的警告.一个纯文本文件,就是干着急打不开.说白了,又是中国特色的 GB <–> UTF-8 文本编码惹的祸.下面小编就给大家带来Mac上打不开txt文件的解决办法. 解决方法很简单:打开「文本编辑.app」,点击屏幕左上角菜单栏的「文本编辑」>「偏好设置-」>「打开和存储」.选择打开纯文本文件的编码为「中文 GB

java获取txt文件内容属性值

问题描述 有一个txt文件,内容如下: <room height="9" width="6"/> <room height="9" width="5"/> <room height="9" width="5"/> 我要循环读取每行,并得到每行的height和width的值,求好代码,谢谢! 解决方案 这种文件如果都是你这种固定格式,可以直接用XML解析

JAVA获取txt文件内容

JAVA 读取txt文件内容 通常,我们可以直接通过文件流来读取txt文件的内容,但有时可能会出现乱码!此时只要设置一下文件字符编码即可. public class txttest { /** * 读取txt文件的内容 * @param file 想要读取的文件对象 * @return 返回文件内容 */ public static String txt2String(File file){ StringBuilder result = new StringBuilder(); try{ Buf

求问如何在C# 窗体中 获取txt文件里的坐标 然后以点的形式显示到picturebox里

问题描述 如题求问如何编程让txt里的坐标点以点的形式显示到窗体的picturebox里 解决方案 解决方案二:你想干嘛,把文字显示为图片?解决方案三:都知道坐标点了,直接画在picturebox上就行了,如果需要换算,你得知道换算规则,然后折算到picturebox内部坐标解决方案四:1.你需要确认你的坐标系,坐标系中心点的位置2.确定pictureBox的大小是根据你已定坐标区域大小的等比缩放,如果存在等比缩放,那么在读取点时候就要处理点的坐标值缩放3.绘制过程,在paint中实现点的绘制就

解析各大搜索引擎对robots.txt文件的反应

中介交易 http://www.aliyun.com/zixun/aggregation/6858.html">SEO诊断 淘宝客 云主机 技术大厅 一直都没有看到个具体的robots.txt文件在各个搜索引擎的执行情况如何,最近,我特意针对robots.txt文件对于各大搜索引擎做了个实验,看他们这一自己说是明文遵守的协议,落实到实际中去执行又是个什么状况.下面我就针对各大搜索引擎对robots.txt文件的反应测试数据,给大家详细讲解下,以供大家平时参考. 首先这个网站在百度,GOOG

将SQL Server中的表变成txt文件

方法一:用BCP命令 bcp 实用工具 bcp 实用工具在 Microsoft? SQL Server? 2000 实例和数据文件之间以用户指定的格式复数据. 语法 bcp {[[database_name.][owner].]{table_name | view_name} | "query"} {in | out | queryout | format} data_file [-m max_errors] [-f format_file] [-e err_file] [-F fir

大神帮忙看下面代码运行后怎么写入txt文件????

问题描述 大神帮忙看下面代码运行后怎么写入txt文件???? #include #include #include #include #include //输入/输出文件流类 using namespace std; const int Maxr=100;//最多的读者 const int Maxb=100;//最多的图书 const int Maxbor=5;//每位读者最多借五本书 //读者类,实现对读者的信息的描述 class Reader { private: int tag; //删除

c++读取txt文件中的数据

问题描述 c++读取txt文件中的数据 有一个txt文件,我想用数组读取其中前3000行的第2,3,7列的数据该怎么办, 解决方案 没什么好办法,好像只能历遍然后逐个获取了. 解决方案二: private void read()?{??InputStream is = null;??DataInputStream dis= null;??int numCount=0;????try??{???is=this.getClass().getResourceAsStream("/level"