2014年02月05日 星期三 20:01
这是我很久之前写的一个程序,当时是为了统计教育网的用户访问量,教育网用户的定义就是其来源IP地址在某个范围中,这个范围是由网络/掩码格式(例如219.220.0.0/16)的文本文件定义的。数据源是经过整理后的web访问日志,格式是“访问量 iP地址”形式。
此程序的主要算法就是将教育网IP地址范围加载到一个bitset容器中,此bitset容器可以覆盖所有IPv4的地址。判断一个IP地址是否在教育网络,只需要判断其对应的bit位是否为1即可,次算法的复杂度为O(1),时间效率很高。此bitset容器占用空间为4Gbits=512MBytes,空间复杂度对于现在的服务器来说,不成问题。
下面是代码,以现在的验光来看,当时还不太熟悉C++,使用了很多C语言的库来完成工作,比如读取文件、拼接字符串等,如果改由C++的iostream、stringstream来完成,应该更好一些。
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <math.h> #include <bitset> #include <climits> using namespace std; long ip2long(char *ip) { long lip=0; if(!ip) { return -1; } char *p1=strchr(ip,'.'); if(!p1) { return -1; } char *p2=strchr(p1+1,'.'); if(!p2) { return -2; } char *p3=strchr(p2+1,'.'); if(!p3) { return -3; } lip+=atol(strndupa(ip,p1-ip)) << 24; lip+=atol(strndupa(p1+1,p2-(p1+1))) << 16; lip+=atol(strndupa(p2+1,p3-(p2+1))) << 8; lip+=atol(p3+1); return lip; } char *long2ip(long ip) { char *sip=(char *)calloc(64,1); unsigned uiip=(unsigned int)ip; sprintf(sip,"%u.%u.%u.%u", ((uiip << 0) >> 24), ((uiip << 8) >> 24), ((uiip << 16) >> 24), ((uiip << 24) >> 24)); return sip; } /* $corr=(pow(2,32)-1)-(pow(2,32-$mask)-1); $first=ip2long($ip) & ($corr); $length=pow(2,32-$mask)-1; */ long get_first_ip(char *cidr, char *mask, long *length) { long lmask=atol(mask); long ip_mask= ~((1 << (32 - lmask)) -1); long first=(ip2long(cidr) & ip_mask) + 1; if(length) { *length=pow(2,32-lmask)-1; } return first; } int main(int argc,char **argv) { if(argc != 2) { printf("usage: %s cidr_files\n",argv[0]); return -1; } FILE *fp=fopen(argv[1],"r"); if(!fp) { perror("fopen:"); return -2; } bitset<UINT_MAX> *bs= new bitset<UINT_MAX>; //bitset<1 > *bs= new bitset<1>; char cidr[64]={0}; int nc=0; char ip[64]={0}; char mask[64]={0}; long j=0; while(!feof(fp)) { //break; memset(cidr,0,sizeof(cidr)); memset(ip,0,sizeof(ip)); memset(mask,0,sizeof(mask)); fgets(cidr,63,fp); nc=strlen(cidr); if(nc <= 7) { if( nc > 1) { printf("bad cidr: %s\n",cidr); } continue; } cidr[nc-1]='\0'; char *slash=strchr(cidr,'/'); if(!slash) { printf("bad cidr: %s\n",cidr); continue; } strncpy(ip,cidr,slash-cidr); strncpy(mask,slash+1,63); long length=0; long first=get_first_ip(ip,mask,&length); for(long i=first;i<(first+length);i++) { bs->set(i); j++; } } fclose(fp); int c=0; char cip[64]; int total=0; while(!feof(stdin)) { fscanf(stdin," %d %s\n",&c,cip); if(ip2long(cip) >= UINT_MAX || ip2long(cip) <=0 ) { printf("invalied ip: %s\n",cip); continue; } if(bs->test(ip2long(cip))) { printf("%d %s\n",c,cip); total+=c; } } printf("total count : %d\n",total); return 0; }
参考资料:
Zeuux © 2024
京ICP备05028076号