一、距离矢量路由协议的特点
1、将所有它知道的路由信息与邻居共享,但是只与直连邻居共享
2、均使用Bellman-Ford(Ford-Fulkerson)算法,必须结合一些防环机制,防止产生路由环路(loop)和计数到无穷大
每台路由器都必须在将从邻居学到的路由转发给其它路由器之前,运行路由算法,所以网络的规模越大,其收敛速度越慢
3、更新的是“路由条目”,一条重要的链路如果发生变化,意味着需通告多条涉及到的路由条目
4、发送周期性更新、完整路由表更新
参考:距离矢量路由协议与链路状态路由协议
二、基本原理
状态转移方程:
1、每个路由器通过测取与相邻路由的距离
2、向相邻路由器周期地发送它到每个目的路由器的距离表
3、同时,接收相邻路由器的距离表
具体更新方法
参考:距离向量路由算法及举例
三、Bellman-Ford算法
1、算法简述
输入:图和源顶点src 输出:从src到所有顶点的最短距离 |
1.初始化:将除源点外的所有顶点的最短距离估计值 dist[v] ← +∞, dist[s] ←0; 2.迭代求解:反复对边集E中的每条边进行松弛操作,使得顶点集V中的每个顶点v的最短距离估计值逐步逼近其最短距离(|v|-1次); 3.检验负权回路:判断边集E中的每一条边的两个端点是否收敛。存在未收敛的顶点,则返回false;否则返回true,并且从源点可达的顶点v的最短距离保存在 dist[v]中。 |
2、例子
3、代码实现
(1)BellmanFord算法
#对所有节点V来说,所有的边E进行松弛操作
def bellman_ford(graph, source):
dist = {}
p = {}
max = 10000
for v in graph:
dist[v] = max # 赋值为负无穷完成初始化
p[v] = source
dist[source] = 0
#遍历所有的边
for i in range(len(graph) - 1):
for u in graph:
for v in graph[u]:
if dist[v] > graph[u][v] + dist[u]:
dist[v] = graph[u][v] + dist[u]
p[v] = u # 完成松弛操作,p为前驱节点
#判断边集E每条边的两个端点是否收敛
for u in graph:
for v in graph[u]:
if dist[v] > dist[u] + graph[u][v]:
return None, None # 判断是否存在环路
#dist:距离 p:前驱节点
return dist, p
(2)测试代码
#测试BellmanFord算法
def test():
graph = {
's': {'t': 6, 'y': 7},
't': {'y': 8, 'z': -4, 'x': 5},
'x': {'t': -2},
'y': {'z': 9, 'x': -3},
'z': {'s': 2, 'x': 7}
}
dist, p = bellman_ford(graph, 's')
print(dist)
print(p)
(3)测试结果
test()
'''
实验结果:
{'x': 4, 'z': -2, 's': 0, 'y': 7, 't': 2}
{'x': 'y', 'z': 't', 's': 's', 'y': 's', 't': 'x'}
'''
参考:Bellman Ford 算法及python实现
四、基于向量算法的路由协议RIP
1、默认,RIP使用简单的度量:通往目的站点所需经过的链路数。取值为1~15,数值16表示无穷大。
2、使用UDP的520端口发送和接收RIP分组。
3、RIP 每隔30秒以广播形式发送一次路由信息,在邻居之间互传。
4、防止广播风暴:后续分组做随机延时后发送。
5、如果一个路由在180s内未被更新,相应的距离设置为无穷大:16,并从路由表中删除该表项。
6、RIP分组分为:请求分组、响应分组
六、代码实现
参考:python实现基于向量算法的路由协议
1、实现的主要函数
(1)add函数:用户输入一个路由信息,便向路由表的集合中添加一组数据
#用户输入一个路由信息,便向路由表的集合中添加一组数据
def add(data,tables):#由用户添加每个路由器的初始路由表
if tables:
flag = False
for i in range(len(tables)):
if data[0] == tables[i][0]:
if [data[1],data[2],data[3]] in tables[i][1]:
string = '路由器%s中已有该表项(目标地址:%s,距离:%d,下一跳:%s)' % (data[0],data[1],data[2],data[3])
else:
tables[i][1].append([data[1],data[2],data[3]])
string = '向路由器%s添加了表项(目标地址:%s,距离:%d,下一跳:%s)' % (data[0],data[1],data[2],data[3])
flag = True
break
if not flag:
tables.append([data[0],[[data[1],data[2],data[3]]]])
string = '添加了%s路由器\n向%s路由器添加了表项(目标地址:%s,距离:%d,下一跳:%s)' % (data[0],data[0],data[1],data[2],data[3])
else:
tables.append([data[0],[[data[1],data[2],data[3]]]])
string = '添加了%s路由器\n向%s路由器添加了表项(目标地址:%s,距离:%d,下一跳:%s)' % (data[0],data[0],data[1],data[2],data[3])
log(string)
return tables
(2)send函数:路由器每次发送自己的路由表的时候调用的函数
#路由器每次发送自己的路由表的时候调用的函数
def send(table):#向相邻网络发送自己的路由表
string = table[0] + '向相邻路由发送了自己的路由表 '
global str_send
str_send += time_now() + '\n' + string + '\n'
(3)update函数:路由器每次更新路由表调用的函数
原理图:
#update函数:路由器每次更新路由表调用的函数
def update(table,tables,table_new):#更新自己的路由表
global str_update
table = copy.deepcopy(table)
tables = copy.deepcopy(tables)
#找出相邻的路由,并且得到更新表
tar = []
for i in table[1]:
if i[1]==1:
tar.append(i[0])
tables.remove(table)
tables_n = copy.deepcopy(tables)
for each in tables:
flag = False
for t in each[1]:
if t[0] in tar and t[1] == 1:
flag = True
break
else:
pass
if not flag:
tables_n.remove(each)
#开始更新
for each in tables_n:
str_update += '\n' + time_now() + '\n路由器%s收到了来自%s的更新表\n' % (table[0],each[0])
table_n = copy.deepcopy(table)
for each in tables_n:
n = each[0]
for tu in each[1]:
tu[1] += 1
if tu[1] == 17:
tu[1] = 16
tu[2] = n
f = False
for t in table_n[1]:
if t[0] == tu[0]:#如果目标网络相同
if t[2] == n:#如果下一跳相同
table_n[1][table_n[1].index(t)] = tu
str_update += '\n' + time_now() + '\n路由器%s从路由器%s更新了表项:\n(目标地址:%s,距离:%d,下一跳:%s)——>\n(目标地址:%s,距离:%d,下一跳:%s)\n' % (table[0],n,t[0],t[1],t[2],tu[0],tu[1],tu[2])
else:#下一跳不同
if (tu[1] < t[1] and t[1] != 16) or tu[1] == 16:
table_n[1][table_n[1].index(t)] = tu
str_update += '\n' + time_now() + '\n路由器%s从路由器%s更新了表项:\n(目标地址:%s,距离:%d,下一跳:%s)——>\n(目标地址:%s,距离:%d,下一跳:%s)\n' % (table[0],n,t[0],t[1],t[2],tu[0],tu[1],tu[2])
f = True
break
if not f:
table_n[1].append(tu)
str_update += '\n' + time_now() + '\n路由器%s从路由器%s添加了新的表项:\n(目标地址:%s,距离:%d,下一跳:%s)\n' % (table[0],n,tu[0],tu[1],tu[2])
#故障处理
for i in table_n[1]:
if i[0] == luyou_wrong and i[1] == 1:
i[1] = 16
lock.acquire()
table_new.append(table_n)
lock.release()
(4)threads函数:为每个路由器的发送和更新路由表分配线程
def threads(tables,table_new):#多线程发送和更新,做到每一个路由器同时发送和更新(设置接收信息的时间为1s)
global str_send
global str_update
str_send = ''
str_update = ''
threadpool_1 = []
for each in tables:
th = threading.Thread(target= send, args= (each,))
threadpool_1.append(th)
for th in threadpool_1:
th.start()
for th in threadpool_1:
threading.Thread.join(th)
t2.config(state = NORMAL)
t2.insert(INSERT,'--------------------------------------------------\n发送情况:\n')
t2.insert(INSERT,str_send)
t2.see(END)
t2.config(state = DISABLED)
time.sleep(1)
threadpool_2 = []
for each in tables:
th = threading.Thread(target= update, args= (each,tables,table_new))
threadpool_2.append(th)
for th in threadpool_2:
th.start()
for th in threadpool_2:
threading.Thread.join(th)
t2.config(state = NORMAL)
t2.insert(INSERT,'--------------------------------------------------\n更新情况:\n')
t2.insert(INSERT,str_update)
t2.see(END)
t2.config(state = DISABLED)
return table_new