首页 > 代码库 > 教你分分钟画出越南全境的主干路由拓扑

教你分分钟画出越南全境的主干路由拓扑

标题党了一次,用一个高大上的的题目先吸引各位看官点进来。

其实原理很简单,我们要做的工作只是做一些数据处理并最终生成kml脚本呈现在Google Earth上。

进入正题:

首先数据来源http://www.caida.org .这是一个英特网数据分析的合作组织,数据比较权威,全球很多网络方面的科研数据都来源于此。

而对本文有用的信息在这里:http://www.caida.org/data/internet-topology-data-kit/  这里面是一些英特网的拓扑信息数据,而且每半年左右都在更新。就从这里获取最新的版本:


进去之后到这个地方:http://data.caida.org/datasets/topology/ark/ipv4/itdk/2011-10/  如图所示:



数据分为两组,是用不同的工具和探测方式获得的,分别是加入使用kapar和不加入,两组数据的区别在于前者更为详尽,而后者更精确。具体探测原理等可以在caida上找到。

我以不添加kapar工具获取的数据为例子。

数据一共有三个文件,其中以.links结尾的路径数据,以.nodes结尾的是节点路由数据,以.nodes.geo结尾的是地理位置数据。

具体的格式等可以见下面的图:


上图是路径数据的文件截图,第一二列是路径的编号。后面N开头的一串数字路由器的编号,后面如果接有IP地址,则是它在路径上的出口,没有即为该接口数据未被探测到。

于是一行数据就代表了一条网络层的路径,每个带编号的路由器就是位于其上的节点。

上图是地理位置文件截图,每一行列出了每个被探测到的路由器的地理位置信息,包括国家,地区,城市,经纬度等


上图是路由器节点数据文件的截图,每一行标识出了每个路由器上的接口的IP地址。


接下来,进行数据处理。思路是,先从地理位置文件把属于越南的路由器筛选出来。然后把这些路由器代入到路径文件里去查找,选出满足条件的路径。最后把这些路由器和路径写入到KML脚本里,用Google Earth读取即可。


写了一个筛选的小程序,把这个过程泛化了一下,可以实现对任何一个国家拓扑脚本的生成。为了赶进度,代码有点乱。。。看官们勿怪。。

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

#define MAX_LINE_SIZE	512 
#define MAX_CITY_NUM	1200 
#define MAX_ROUTE_NUM	100000 

typedef struct Route_info{
//	char fileinfo[10];
	char route_id[10];
//	char continent[5];
	char country[5];
//	char region[6];
	char city[25];
	float latitude;
	float longtitude;
}Route_info;

typedef struct Location {
	float latitude;
	float longtitude;
}Location;

char city_list[MAX_CITY_NUM][25];
int current_citynum = 0;

Route_info routeinfo_set[MAX_ROUTE_NUM];  //route_id include character ':'
int routeinfo_index = 0;

Location location_set[MAX_CITY_NUM];
int location_index = 0;

int get_line(int *fd, char* line_buf, int line_size)
{
	int a, i = 0;
	memset(line_buf, 0, MAX_LINE_SIZE);
	while (((a = getchar()) != '\n' && a != EOF) && i < line_size-2) //mark
		line_buf[i++] = a;

	line_buf[i] = '\n'; //add \n to process data convinently
	if (a == -1)
		return 0;
	else
		return i+1;  //include \n
}

int read_raw_linkfile(char *postfix)
{
	int fd_in, fd_out, line_size;
	char line_buf[MAX_LINE_SIZE], outfile_name[20];
	if ((fd_in = open("./midar-iff.links.in", O_RDONLY)) == -1) {
		perror("Fail to open:");
		return 0;
	}

	memset(outfile_name, 0, 20);
	strcpy(outfile_name, "link.");
	strcat(outfile_name, postfix);

	if ((fd_out = open(outfile_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR)) == -1) {
		perror("Fail to open:");
		return 0;
	}
	dup2(fd_in, STDIN_FILENO);
	
	printf("fetching %s's link data...\n", postfix);
	while (line_size = get_line(STDIN_FILENO, line_buf, MAX_LINE_SIZE))
	{
		if (line_buf[0] == '#')
			continue;
		if (check_link(line_buf))
			write(fd_out, line_buf, line_size);
	}

	close(fd_in);
	close(fd_out);
	return 1;
}

void get_location(char *line_buf)
{
	char *ptr = line_buf;
	int len = strlen(line_buf);
	ptr += (len - 2);
	while ((*ptr >= 48 && *ptr <= 57) || *ptr == '\t' || *ptr == '.' /*|| *ptr == 32*/) ptr--;
	ptr++; //mark
	sscanf(ptr, "%f %f", &location_set[location_index].latitude, &location_set[location_index].longtitude);
	location_index++;
}

void get_routeinfo(char *line_buf)
{
	char id_tmp[10], *ptr;
	memset(id_tmp, 0, 10);
	sscanf(line_buf, "%*s %s", routeinfo_set[routeinfo_index].route_id);


	/* drop char ':' */
	//for (ptr = id_tmp; *ptr != ':'; ptr++);
//	memcpy(routeinfo_set[routeinfo_index].route_id, id_tmp, ptr - id_tmp);

	ptr = line_buf;
	int len = strlen(line_buf);
	ptr += (len - 2);
	while ((*ptr >= 48 && *ptr <= 57) || *ptr == '\t' || *ptr == '.' ) ptr--;
	ptr++; //mark
	sscanf(ptr, "%f %f", &routeinfo_set[routeinfo_index].latitude, &routeinfo_set[routeinfo_index].longtitude);
	routeinfo_index++;
}

int read_raw_routefile(char *postfix)
{
	int fd_in, fd_out, fd_out_norep, line_size;
	char line_buf[MAX_LINE_SIZE], outfile_name[20], outfilenorep_name[20];
	if ((fd_in = open("./midar-iff.nodes.geo.in", O_RDONLY)) == -1) {
		perror("Fail to open:");
		return 0;
	}

	memset(outfile_name, 0, 20);
	strcpy(outfile_name, "route.");
	strcat(outfile_name, postfix);

	memset(outfilenorep_name, 0, 20);
	strcpy(outfilenorep_name, "route_city.");
	strcat(outfilenorep_name, postfix);

	if ((fd_out = open(outfile_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR)) == -1) {
		perror("Fail to open:");
		return 0;
	}

	if ((fd_out_norep = open(outfilenorep_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR)) == -1) {
		perror("Fail to open:");
		return 0;
	}

	dup2(fd_in, STDIN_FILENO);
	
	Route_info rinfo;
	while (line_size = get_line(STDIN_FILENO, line_buf, MAX_LINE_SIZE))
	{
		if (line_buf[0] == '#')
			continue;
		memset((char*)&rinfo, 0, sizeof(Route_info));
		sscanf(line_buf, "%*s %s %*s %s %*s %s \t%f %f", rinfo.route_id, rinfo.country, rinfo.city, &rinfo.latitude, &rinfo.longtitude);
		if (!strcmp(rinfo.country, postfix)) {
			if (!check_cityrepeatition(rinfo.city)) {
				write(fd_out_norep, line_buf, line_size);
				get_location(line_buf);
			}

			get_routeinfo(line_buf);
			//strcpy(route_list[current_routenum++], rinfo.route_id);
			write(fd_out, line_buf, line_size);
		}
	}

	close(fd_in);
	close(fd_out);
	return 1;
}


void print_locationset()
{
	int i;
	for (i = 0; i < location_index; i++)
		printf("%f %f\n",location_set[i].latitude, location_set[i].longtitude);
}
void print_routeinfoset()
{
	int i;
	for (i = 0; i < routeinfo_index; i++)
		printf("%s %f %f\n", routeinfo_set[i].route_id, routeinfo_set[i].latitude, routeinfo_set[i].longtitude);
}
/* drop the repeative city */
int check_cityrepeatition(char *city)
{
	int i;
	for (i = 0; i < current_citynum; i++)
	{
		if (!strcmp(city, city_list[i]))
			return 1;
	}

	strcpy(city_list[current_citynum++], city);
	return 0;
}

/* at least two adjacent route on the link */
int check_link(char *line_buf)
{
	char *ptr = line_buf, route_id[10], *tmp;
	int i, pre_flag = 0;
	while (*ptr != '\n' && *ptr != EOF)
	{
		memset(route_id, 0, 10*sizeof(char));
		ptr = strchr(ptr, 'N');
		if (!ptr)
			break;
		tmp = ptr;
		while (*tmp != ' ' && *tmp != ':' && *tmp != '\n') tmp++;
		for (i = 0; (ptr + i) < tmp; i++)
			route_id[i] = *(ptr+i);
		route_id[i] = ':';          //match the format
		if (check_route(route_id)) {
			if (pre_flag)
				return 1;
			else 
				pre_flag = 1;

		}
		else 
			pre_flag = 0;
		ptr = tmp;
	}
	return 0;
}

int check_route(char *route_id) 
{
	int i;
	for (i = 0; i < routeinfo_index; i++)
		if (!strcmp(routeinfo_set[i].route_id, route_id)) {
			return 1;
		}
	return 0;
}

void draw_route(char *kmlfile_name)
{
	int i, fd_out;
	char buf[1024];

	if ((fd_out = open(kmlfile_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR)) == -1) {
		perror("Fail to open:");
		return;
	}
	printf("generate the routes kml file...\n");

	memset(buf, 0, 1024);
	sprintf(buf, "<Document>\n<Style id=\"icon_style\">\n<IconStyle>\n<Icon>\n<href>juanjo_Router.png</href>\n</Icon>\n<scale>0.8</scale>\n</IconStyle>\n</Style>\n");
	write(fd_out, buf, strlen(buf));
	memset(buf, 0, 1024);

	for (i = 0; i < location_index; i++)
	{
		sprintf(buf, "<Placemark>\n<styleUrl>#icon_style</styleUrl>\n<Point>\n<coordinates>%f,%f,0</coordinates>\n</Point>\n</Placemark>\n", location_set[i].longtitude, location_set[i].latitude);
		write(fd_out, buf, strlen(buf));
		memset(buf, 0, 1024);
	}

	close(fd_out);
}


void get_routeloca(char *route_id, float* lati, float* longti)
{
	int i;
	for (i = 0; i < routeinfo_index; i++)
		if (!strcmp(routeinfo_set[i].route_id, route_id)) {
			*lati = routeinfo_set[i].latitude;
			*longti = routeinfo_set[i].longtitude;
			return;
		}
}

void get_endofline(char*line_buf, float* start_la, float* start_long, float* end_la, float* end_long)
{
	char *ptr = line_buf, route_id[10], *tmp;
	int i, pre_flag = 0;
	while (*ptr != '\n' && *ptr != EOF)
	{
		memset(route_id, 0, 10*sizeof(char));
		ptr = strchr(ptr, 'N');
		if (!ptr)
			break;
		tmp = ptr;
		while (*tmp != ' ' && *tmp != ':' && *tmp != '\n') tmp++;
		for (i = 0; (ptr + i) < tmp; i++)
			route_id[i] = *(ptr+i);
		route_id[i] = ':';          //match the format
		if (check_route(route_id)) {
			if (pre_flag) {
				get_routeloca(route_id, end_la, end_long);
				return ;
			}
			else {
				get_routeloca(route_id, start_la, start_long);
				pre_flag = 1;
			}
		}
		else 
			pre_flag = 0;
		ptr = tmp;
	}
	return ;
}

void draw_line(char* postfix, char *kmlfile_name)
{
	int fd_in, fd_out, line_size;
	char file_name[20], buf[1024], line_buf[MAX_LINE_SIZE];
	Location start, end;

	memset(file_name, 0, 20);
	strcpy(file_name, "link.");
	strcat(file_name, postfix);

	if ((fd_in = open(file_name, O_RDONLY)) == -1) {
		perror("Fail to open:");
		return ;
	}

	if ((fd_out = open(kmlfile_name, O_RDWR | O_APPEND)) == -1) {
		perror("Fail to open:");
		return ;
	}

	dup2(fd_in, STDIN_FILENO);
	
	printf("generate the link between routes...\n");

	sprintf(buf, "<Style id=\"color_line\">\n<LineStyle>\n<color>ff00FF00</color>\n<width>2</width>\n</LineStyle>\n</Style>\n");
	write(fd_out, buf, strlen(buf));
	memset(buf, 0, 1024);

	while (line_size = get_line(STDIN_FILENO, line_buf, MAX_LINE_SIZE))
	{
		get_endofline(line_buf, &start.latitude, &start.longtitude, &end.latitude, &end.longtitude);
		sprintf(buf, "<Placemark>\n<styleUrl>#color_line</styleUrl>\n<LineString>\n<extrude>0</extrude>\n<tessellate>1</tessellate>\n<altitudeMode>clampToGround</altitudeMode>\n<coordinates>\n%f,%f,0\n%f,%f,0\n</coordinates>\n</LineString>\n</Placemark>\n", start.longtitude, start.latitude, end.longtitude, end.latitude);
		write(fd_out, buf, strlen(buf));
		memset(buf, 0, 1024);
	}

	sprintf(buf, "</Document>\n");
	write(fd_out, buf, strlen(buf));

	printf("Success to generate the %s's kml files\n", postfix);
	close(fd_in);
	close(fd_out);
}

int main(int argc, char* argv[])
{
	if (argc != 2) {
		printf("Usage: ./<pram> <country_name>");
		return 1;
	}

	char kmlfile_name[20];

	memset(kmlfile_name, 0, 20);
	strcpy(kmlfile_name, argv[1]);
	strcat(kmlfile_name, ".kml");
	

	if (read_raw_routefile(argv[1]))
		printf("Success to read %s's data from raw route data file\n", argv[1]);

	print_locationset();

	print_routeinfoset();

	draw_route(kmlfile_name);

	if (read_raw_linkfile(argv[1]))
		printf("Success to read %s's data from raw link data file\n", argv[1]);

	draw_line(argv[1], kmlfile_name);
	return 0;
}

程序执行有生成两个临时的文件,分别是过滤出的国家的路由和链路,如图,越南的数据如下:





最终得到KML文件:


最后的效果如图所示:



看到图像有点小小的激动,博主根本挺不下来,又把小日本弄来玩了一把,奈何日本土地稀缺却网络发达,图像太拥挤非常不利于观摩,上个图作为结尾吧