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 © 2025
京ICP备05028076号