C Programer  - 讨论区

标题:使用STL bitset容器统计区域用户访问量

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;
}

参考资料:

http://www.cplusplus.com/reference/bitset/bitset/

如下红色区域有误,请重新填写。

    你的回复:

    请 登录 后回复。还没有在Zeuux哲思注册吗?现在 注册 !

    Zeuux © 2024

    京ICP备05028076号