RIP协议的距离向量算法实现(c++)

模拟路由表示意图

核心:

  • 新的直接进表
  • 下一跳不一样要短的
  • 下一跳一样要新的(哪怕更长)

(应用层的不是网络层的)

解释: eg:x收到相邻结点的路由表信息,则

(规定路由器直接相邻的网络距离为1)
1.先将下一跳全改为X
2.距离全部+1
3.
    3.1 新的直接进表:X路由表没有对应目的网络相同的路由信息
    3.2 下一跳相同要新的: X路由表有对应目的网络相同且下一跳相同的路由项,要新的路由项 (网络拓扑可能变化了,否则就不是坏消息传得慢了,而是压根发现不了坏消息(网络某链路坏了))
     3.3 下一跳不同要短的:X路由表有对应目的网络相同但下一跳不同的路由项,要距离短的

算法实现:

#include<iostream>
#include<fstream>
#include<algorithm>
#include<string>
#include<vector>
#include<cstdio>
#include<unistd.h>
#include<sys/time.h>
using namespace std;

const int maxR=6;//最大路由器数量

//时间间隔辅助函数
typedef long long ll;
ll getNowTime(){//返回秒数
	struct timeval tv;
	struct timezone tz;
	gettimeofday(&tv,&tz);
	return tv.tv_sec;//零头的微秒忽略
}

//路由表项
struct RIP{
	char name;//本路由器名称
	int N;//到目的网络N
	int d;//距离d
	char X;//下一跳路由器
	ll time;//上次更新时间
	bool is_valid;//是否有效
	RIP(){is_valid=true;}
};

//发送的报文打包
vector<RIP> Send(vector<RIP> r,char c){
	for(int i=0;i<r.size();i++){
		r[i].d++;
		r[i].X=c;
		r[i].time=getNowTime();//时间也要更新
	}
	return r;
}

vector<RIP> rip[maxR];//路由表
char idToRname[]="ABCDEF";//int编号改为字母标号 0-A 1-B 2-C 3-D 4-E 5-F
vector<char> ve[maxR];//一个vector<RIP>包含多条记录是一个路由表 ve则可表示路由器分布图邻接表

//打印路由表
void printR(){
	vector<RIP> r;
	for(int i=0;i<maxR;i++){
		r=rip[i];
		cout<<"***********************路由表"<<idToRname[i]<<"************************\n";
		cout<<"到目的网络N\t\t距离d\t\t下一跳路由器X\n";
		for(int i=0;i<r.size();i++){
			cout<<r[i].N<<"\t\t\t"<<r[i].d<<"\t\t"<<r[i].X<<endl;
		}
	}
}

//用文件file的内容更新各个路由器
void init(char* file){
	fstream infile(file);
	if(!infile.is_open()) cout<<"未成功打开文件!"<<endl;
	int N;char name;RIP rp;
	infile>>N;
	for(int i=0;i<N;i++){//此处N和maxR设置得一样大 当然可小不可大
		infile>>name;//因为按顺序的所以不处理了
		rp.name=name;//处理下也行 不过一次处理一次就够了  冗余但安全性高了
		while(infile>>rp.N>>rp.d>>rp.X&&rp.N){
			rp.time=getNowTime();
			rip[i].push_back(rp);
		}
	}
	infile.close();
}

//用领接表初始化网络结构图
void initve(char* file){
	fstream infile(file);
	if(!infile.is_open()) cout<<"未成功打开文件!"<<endl;
	char v,v1;
	while(infile>>v){//第一个是当前结点 后面的都是当前结点的所有邻居 0表示结束
		while(infile>>v1&&v1!='0'){
			ve[v-'A'].push_back(v1);
		}
	}
	infile.close();
}

//打印图
void printG(){
	cout<<"**********************网络拓扑结构********************\n";
	for(int i=0;i<maxR;i++){
		cout<<char(i+'A')<<" ";
		for(int j=0;j<ve[i].size();j++){
			cout<<ve[i][j];
			if(j<ve[i].size()-1) cout<<" ";
		}
		cout<<endl;
	}
}

//路由表排序依据
bool cmp(RIP r1,RIP r2){
	return r1.N<r2.N;
}

//正式发送更新报文更新路由表了
bool update(){
	bool hasEdit=false;//本次更新有无修改
	vector<RIP> send;
	vector<RIP> rip1[maxR];
	for(int i=0;i<maxR;i++) rip1[i]=rip[i];//不一定赋值成功
	for(int i=0;i<maxR;i++){//遍历每个路由结点
		//rip里是本次更新前所有路由表的状态   rip1是更新过程中每个路由表的状态 
		//为了达到同时发送不产生连锁效应 故先备份新状态rip1 全部更新完毕再一次性协会rip

		//传旧的         i号结点传的
		send=Send(rip[i],i+'A');//向邻居发送的路由更新报文 i就是路由器编号 rip和ve的存储顺序一致

		for(int j=0;j<ve[i].size();j++){//遍历第i个路由器的所有邻居 目的就是更新邻居啊
			//本次给邻居ve[i][j] 一个字母 -'A'就是序号
			int lid=ve[i][j]-'A';
			for(int x=0;x<send.size();x++){//一条一条遍历发过来的更新报文 一条一条插入
				int k;
				//检查筛选时要筛选新的
				for(k=0;k<rip1[lid].size();k++){//遍历邻居路由表 查找更新报文的每一条
					//开始rip1是rip的备份 新的都写到rip1里    
					/*rip[lid]是第lid个路由表  rip[lid][k]是第lid个路由表的第k条记录*/
					if(send[x].N==rip1[lid][k].N){//有 判断逻辑:目的地址相同
						if(send[x].X==rip1[lid][k].X){//下一跳相同 要新的
							if(rip1[lid][k].d!=send[x].d){//N X d都相同  更新却无任何更改(仅仅改时间...)
								rip1[lid][k]=send[x];
								hasEdit=true;
							} 

						}else{//下一跳不同要短的
							if(send[x].d<rip1[lid][k].d){
								rip1[lid][k]=send[x];
								hasEdit=true;
							}
						}
						break;
					}
				}

				if(k==rip1[lid].size()){//没找到 是新的 直接加入
					rip1[lid].push_back(send[x]);
					hasEdit=true;
				}
			}			
		}
	}

	//一次更新完毕 才写回rip
	for(int i=0;i<maxR;i++) {
		rip[i]=rip1[i];//不一定赋值成功
		sort(rip[i].begin(),rip[i].end(),cmp);//按目的地址排序
	}
	return hasEdit;//返回本次有无更改
}

//检查有无长期未更新的路由表项
void check(){
	ll t1=getNowTime();
	for(int i=0;i<maxR;i++){
		for(int j=0;j<rip[i].size();j++){
			if(rip[i][j].is_valid&&(t1-rip[i][j].time)>180) rip[i][j].is_valid=false;//180s无更新 标记无效
			else if(!rip[i][j].is_valid&&(t1-rip[i][j].time)>120) rip[i].erase(rip[i].begin()+j);//无效后120s无更新 删除
		}
	}
}

int main(){
	// freopen("运行结果.txt","w",stdout);
	init("routes.txt");//用文件routes.txt初始化
	printR();
	initve("netGraphic.txt");//初始化网络拓扑图
	printG();
	int T=0,n=0;
	while(true){
		sleep(1);//每隔3秒更新路由表 为了演示运行结果方便不设置为30s秒了
		cout<<"\n------------------------第"<<++T<<"次更新------------------------\n";
		if(update()){//一次更新
			printR();//打印路由表
			n++;
		}else{
			cout<<"本次没有任何有价值的修改!说明前面"<<n<<"次修改后,每一个路由器都得到了全局路由信息!\n";
		}
		check();
	}
	return 0;
}

文件:

netGraphic.txt 网络拓扑图 0代表一行结束

A B D E 0
B A C 0
C B F 0
D A E F 0
E A D F 0
F C D E 0

routes.txt 各个路由表初始状态

6

A
1 1 -
2 1 -
3 1 -
0 0 0

B
3 1 -
4 1 -
0 0 0

C
4 1 -
6 1 -
0 0 0

D
2 1 -
5 1 -
0 0 0

E
1 1 -
5 1 -
0 0 0

F
5 1 -
6 1 -
0 0 0

#第一个数字N表示路由器个数
#N组,每组表示一个路由器表项 每个路由器表项中目的网络为0表示此路由器结束

3个文件要放在同一个文件夹下执行

运行结果:

***********************路由表A************************
到目的网络N		距离d		下一跳路由器X
1				1			-
2				1			-
3				1			-
***********************路由表B************************
到目的网络N		距离d		下一跳路由器X
3				1			-
4				1			-
***********************路由表C************************
到目的网络N		距离d		下一跳路由器X
4				1			-
6				1			-
***********************路由表D************************
到目的网络N		距离d		下一跳路由器X
2				1			-
5				1			-
***********************路由表E************************
到目的网络N		距离d		下一跳路由器X
1				1			-
5				1			-
***********************路由表F************************
到目的网络N		距离d		下一跳路由器X
5				1			-
6				1			-
**********************网络拓扑结构********************
A B D E
B A C
C B F
D A E F
E A D F
F C D E

------------------------第1次更新------------------------
***********************路由表A************************
到目的网络N		距离d		下一跳路由器X
1				1			-
2				1			-
3				1			-
4				2			B
5				2			D
***********************路由表B************************
到目的网络N		距离d		下一跳路由器X
1				2			A
2				2			A
3				1			-
4				1			-
6				2			C
***********************路由表C************************
到目的网络N		距离d		下一跳路由器X
3				2			B
4				1			-
5				2			F
6				1			-
***********************路由表D************************
到目的网络N		距离d		下一跳路由器X
1				2			A
2				1			-
3				2			A
5				1			-
6				2			F
***********************路由表E************************
到目的网络N		距离d		下一跳路由器X
1				1			-
2				2			A
3				2			A
5				1			-
6				2			F
***********************路由表F************************
到目的网络N		距离d		下一跳路由器X
1				2			E
2				2			D
4				2			C
5				1			-
6				1			-

------------------------第2次更新------------------------
***********************路由表A************************
到目的网络N		距离d		下一跳路由器X
1				1			-
2				1			-
3				1			-
4				2			B
5				2			D
6				3			B
***********************路由表B************************
到目的网络N		距离d		下一跳路由器X
1				2			A
2				2			A
3				1			-
4				1			-
5				3			A
6				2			C
***********************路由表C************************
到目的网络N		距离d		下一跳路由器X
1				3			B
2				3			B
3				2			B
4				1			-
5				2			F
6				1			-
***********************路由表D************************
到目的网络N		距离d		下一跳路由器X
1				2			A
2				1			-
3				2			A
4				3			A
5				1			-
6				2			F
***********************路由表E************************
到目的网络N		距离d		下一跳路由器X
1				1			-
2				2			A
3				2			A
4				3			A
5				1			-
6				2			F
***********************路由表F************************
到目的网络N		距离d		下一跳路由器X
1				2			E
2				2			D
3				3			C
4				2			C
5				1			-
6				1			-

------------------------第3次更新------------------------
本次没有任何有价值的修改!说明前面2次修改后,每一个路由器都得到了全局路由信息!

------------------------第4次更新------------------------
本次没有任何有价值的修改!说明前面2次修改后,每一个路由器都得到了全局路由信息!

------------------------第5次更新------------------------
本次没有任何有价值的修改!说明前面2次修改后,每一个路由器都得到了全局路由信息!

------------------------第6次更新------------------------
本次没有任何有价值的修改!说明前面2次修改后,每一个路由器都得到了全局路由信息!

------------------------第7次更新------------------------
本次没有任何有价值的修改!说明前面2次修改后,每一个路由器都得到了全局路由信息!

------------------------第8次更新------------------------
本次没有任何有价值的修改!说明前面2次修改后,每一个路由器都得到了全局路由信息!

------------------------第9次更新------------------------
本次没有任何有价值的修改!说明前面2次修改后,每一个路由器都得到了全局路由信息!

------------------------第10次更新------------------------
本次没有任何有价值的修改!说明前面2次修改后,每一个路由器都得到了全局路由信息!

用C写的rip协议 这是其中的广播request程序片段: void RouteInit() { int i,optval=0,length,error; routeNum = 0; // init local socket address and ip address GetLocalIP(); // init route table items for(i = 0; i < MAX_NUM; i++) { SetRouteEntry(&routeTable[i].routeInfo,"0.0.0.0",0,0); routeTable[i].isvalid = 0; routeTable[i].timer = 0; routeTable[i].statue = 0; inet_aton("0,0,0,0",&routeTable[i].sourceIPAddr); } // init request packet SetRoutePacket(&reqPacket,REQUEST); SetRouteEntry(&reqPacket.routeEntry[0],"0.0.0.0",0,16); // init response packet SetRoutePacket(&resPacket,RESPONSE); recvSockAddr.sin_family = AF_INET; recvSockAddr.sin_port = htons(PORT); recvSockAddr.sin_addr.s_addr = htonl(INADDR_ANY); sendSockAddr.sin_family = AF_INET; sendSockAddr.sin_port = htons(PORT); // inet_aton("240.255.255.255",&sendSockAddr.sin_addr); sendSockAddr.sin_addr.s_addr = htonl(INADDR_ANY); EntryInit(); sock = socket(AF_INET,SOCK_DGRAM,0); if(sock<0) { printf("cannot create a socket!\n"); exit(1); } if(setsockopt(sock,SOL_SOCKET,SO_BROADCAST,&optval,sizeof(int)) != 0) { printf("cannot broadcast!\n"); close(sock); exit(1); } if(bind(sock,(struct sockaddr*)&recvSockAddr,sizeof(recvSockAddr))<0) { printf("cannot bind to port\n"); close(sock); exit(1); } length=sizeof recvSockAddr; getsockname(sock,(struct sockaddr*)&recvSockAddr,&length); printf("Port %d is opened. Listen for packet...\n",ntohs(recvSockAddr.sin_port)); FD_ZERO(&fdSet); FD_SET(sock,&fdSet); error = sendto(sock,&reqPacket,4+sizeof(struct ROUTE_ENTRY),0,(struct sockaddr*)(&sendSockAddr),sizeof(struct sockaddr)); if(error<0) { PrintEntry(&reqPacket.routeEntry[0]); printf("broadcast request packet failed! %d,%d,%d\n",error,sock,fdSet); } }
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值