C语言sprintf与sscanf函数
1、前言
OUI是指Organizationally unique identifier ?(組織唯一標(biāo)識(shí)符),簽發(fā)給各類組織的唯一標(biāo)識(shí)符。MAC地址共有6個(gè)字節(jié)48位組成,前3個(gè)字節(jié)體現(xiàn)了OUI,其表明了NIC的制造組織。通常情況下,該標(biāo)識(shí)符是唯一的。詳細(xì)介紹參考:http://standards.ieee.org/develop/regauth/oui/public.html。oui.txt文件中記錄世界所有網(wǎng)卡的制造廠商,共有18859個(gè)。文件中記錄mac的前三位與公司的對(duì)應(yīng)關(guān)系。本文目地是對(duì)oui.txt文件進(jìn)行解析,生產(chǎn)一個(gè)信息的文件,在程序中可以根據(jù)制定的mac地址,快速查找其對(duì)應(yīng)的公司名稱。在此將MAC前三個(gè)字節(jié)簡(jiǎn)稱為MAC前綴。
2、初步處理
oui.txt文件內(nèi)容很有規(guī)律,根據(jù)MAC前綴由小到大記錄。但是,MAC前綴并不是連續(xù)的,中間有些間斷,但是順序是由小到大。原始文件內(nèi)容格式如下所示:
OUI Organizationcompany_id OrganizationAddress00-00-00 (hex) XEROX CORPORATION000000 (base 16) XEROX CORPORATIONM/S 105-50C800 PHILLIPS ROADWEBSTER NY 14580UNITED STATES00-00-01 (hex) XEROX CORPORATION000001 (base 16) XEROX CORPORATIONZEROX SYSTEMS INSTITUTEM/S 105-50C 800 PHILLIPS ROADWEBSTER NY 14580UNITED STATES00-00-02 (hex) XEROX CORPORATION000002 (base 16) XEROX CORPORATIONXEROX SYSTEMS INSTITUTEM/S 105-50C 800 PHILLIPS ROADWEBSTER NY 14580UNITED STATES 文件中網(wǎng)卡前綴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文件內(nèi)容如下:
00-00-00 (hex) XEROX CORPORATION00-00-01 (hex) XEROX CORPORATION00-00-02 (hex) XEROX CORPORATION00-00-03 (hex) XEROX CORPORATION00-00-04 (hex) XEROX CORPORATION00-00-05 (hex) XEROX CORPORATION00-00-06 (hex) XEROX CORPORATION更進(jìn)一步抽取mac和org信息,可以對(duì)mac_hex_org.txt文件進(jìn)行提前,采用一個(gè)簡(jiǎn)單的shell腳本,提前mac列和org列,分別保存在MAC.log和ORG.log文件中。shell腳本mac_org.sh如下:
#!/bin/sh SRC_FILE=mac_hex_org.txt MAC_FILE=MAC.log ORG_FILE=ORG.log cat ${SRC_FILE} |grep -v "^#" | while read line; doecho "${line:0:8}" >> ${MAC_FILE}echo "${line:18}">>${ORG_FILE} done執(zhí)行mac_org.sh生產(chǎn)MAC.log和ORG.log文件。兩個(gè)文件的每行對(duì)應(yīng)關(guān)系就是mac前綴與公司名稱的關(guān)系。文件內(nèi)容如下所示:
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、生產(chǎn)mac-org結(jié)構(gòu)文件
為了在程序快速查找,將MAC.log和ORG.log文件中對(duì)應(yīng)關(guān)系轉(zhuǎn)換為一個(gè)結(jié)構(gòu)體,存入mac_org.log文件中。mac前綴是唯一的,對(duì)應(yīng)轉(zhuǎn)換為10進(jìn)制的整數(shù),相比字符串,查找更加方便。mac_org結(jié)構(gòu)定義如下:
//mac前綴和公司名稱對(duì)應(yīng)關(guān)系 typedef struct mac_org {uint32_t key; //mac前綴作為keychar org_name[ORG_NAME_LEN]; //公司名稱 }mac_org;在程序中分別讀取MAC.log和ORG.log的每一行,轉(zhuǎn)換為一個(gè)mac_log結(jié)構(gòu),寫(xiě)入mac_log.log文件。轉(zhuǎn)換程序如下所示:
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前綴長(zhǎng)度10 #define ORG_NAME_LEN 96 //公司名稱長(zhǎng)度11 #define MAC_LOG_FILE "MAC.log" //mac前綴文件12 #define ORG_LOG_FILE "ORG.log" //公司名稱文件13 #define MAC_ORG_FILE "mac2org.log" //mac前綴對(duì)應(yīng)公司名稱文件14 15 #define PRINT_ERROR_POS() do{ \16 printf("File: "__FILE__", Line:%d\n", __LINE__); \17 }while(0);18 19 //mac前綴和公司名稱對(duì)應(yīng)關(guān)系20 typedef struct mac_org21 {22 uint32_t key; //mac前綴作為key23 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前綴轉(zhuǎn)換為數(shù)字,前綴格式為:00-00-0032 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結(jié)構(gòu),并將結(jié)果存入文件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 //設(shè)置記錄值88 tmp.key = macprefix2uint(mac_buf);89 strcpy(tmp.org_name,org_buf);90 //將該記錄寫(xiě)入文件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 }執(zhí)行程序:
查看mac2org.log文件大小和內(nèi)容如下:文件是二進(jìn)制形式存入。
4、根據(jù)mac前綴在mac2org.log查找org
mac2org.log文件結(jié)構(gòu)很明確,而且文件大小僅為1.8MB,完全可以將文件內(nèi)容全部讀到內(nèi)存進(jìn)行查找。而且mac2org.log記錄是根據(jù)mac前綴有小到大的,即讀到內(nèi)存中的buffer中,mac_org記錄是有序的,可以采用折半查找進(jìn)行,以mac前綴轉(zhuǎn)換的整數(shù)為key。查找程序如下所示:
1 /**根據(jù)mac前綴(形如00-00-00)查找organzation2 先將mac_org.log讀取到內(nèi)存,然后進(jìn)行折半查找3 @auther: Anker @date:2013-12-184 **/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前綴長(zhǎng)度14 #define ORG_NAME_LEN 96 //公司名稱長(zhǎng)度15 #define MAC_TYPE_COUNT 18860 //記錄個(gè)數(shù)16 #define MAC_ORG_FILE "mac2org.log" //mac前綴對(duì)應(yīng)公司名稱文件17 18 #define PRINT_ERROR_POS() do{ \19 printf("File: "__FILE__", Line:%d\n", __LINE__); \20 }while(0);21 22 //mac前綴和公司名稱對(duì)應(yīng)關(guān)系23 typedef struct mac_org24 {25 uint32_t key; //mac前綴作為key26 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前綴轉(zhuǎn)換為數(shù)字,前綴格式為:00-00-0035 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 //二分查找過(guò)程44 int32_t binary_search(mac_org *macorg, int32_t n, uint32_t key)45 {46 //在有序表macorg[0..n-1]中進(jìn)行二分查找,成功時(shí)返回結(jié)點(diǎn)的位置,失敗時(shí)返回-147 int32_t low = 0, high = n-1, mid; //置當(dāng)前查找區(qū)間上、下界的初值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 //當(dāng)前查找區(qū)間macorg[low..high]非空59 mid = low + ((high - low) / 2);60 //使用 (low + high) / 2 會(huì)有整數(shù)溢出的問(wèn)題61 //(問(wèn)題會(huì)出現(xiàn)在當(dāng)low + high的結(jié)果大于表達(dá)式結(jié)果類型所能表示的最大值時(shí),62 //這樣,產(chǎn)生溢出后再/2是不會(huì)產(chǎn)生正確結(jié)果的,而low+((high-low)/2)不存在這個(gè)問(wèn)題63 if(macorg[mid].key == key)64 {65 return mid; //查找成功返回66 }67 if(macorg[mid].key > key)68 {69 high = mid - 1; //繼續(xù)在macorg[low..mid-1]中查找70 }71 else72 {73 low = mid + 1; //繼續(xù)在macorg[mid+1..high]中查找74 }75 }76 return -1; //當(dāng)low>high時(shí)表示查找區(qū)間為空,查找失敗77 }//BinSeareh78 79 //給定一個(gè)mac前綴,獲取對(duì)應(yīng)的公司名稱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 }測(cè)試結(jié)果如下所示:
采用折半查找,針對(duì)18860條記錄,查詢時(shí)間不足1秒,非常之快。
5、總結(jié)
? ? ?剛開(kāi)始拿到oui.txt文件時(shí),看了文件的格式和規(guī)律。當(dāng)時(shí)沒(méi)有檢查,以為mac前綴是連續(xù)的,如是開(kāi)始第一個(gè)想到用hash做,mac前綴作為key,value是mac-key在文件中的偏移量。因?yàn)閔ash是唯一的,轉(zhuǎn)換為整數(shù),不會(huì)有沖突。實(shí)現(xiàn)后發(fā)現(xiàn)生產(chǎn)的mac_org.log文件1.2G之大,文件中有很多空白地方,排查發(fā)現(xiàn)mac前綴并不是連續(xù)的,而且MAC前綴還存在重復(fù)。如下圖所示:
故不可以采用hash實(shí)現(xiàn)。最后還是采用將文件內(nèi)容記載到內(nèi)存處理。mac_log結(jié)構(gòu)的占用100字節(jié),18860條共計(jì)約1.8MB,如今內(nèi)存都已GB計(jì)算,完全可以全部加載到內(nèi)存進(jìn)行二分查找。
6、參考網(wǎng)址
http://my.oschina.net/duangr/blog/183789
冷靜思考,勇敢面對(duì),把握未來(lái)!
總結(jié)
以上是生活随笔為你收集整理的C语言sprintf与sscanf函数的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 怎么拾取pe里的移动硬盘 在PE环境下如
- 下一篇: pe下怎么连接手机版 PE如何连接手机版