距离向量路由相关原理及实现

一、距离矢量路由协议的特点

1、将所有它知道的路由信息与邻居共享,但是只与直连邻居共享

2、均使用Bellman-Ford(Ford-Fulkerson)算法,必须结合一些防环机制,防止产生路由环路(loop)和计数到无穷大

每台路由器都必须在将从邻居学到的路由转发给其它路由器之前,运行路由算法,所以网络的规模越大,其收敛速度越慢

3、更新的是“路由条目”,一条重要的链路如果发生变化,意味着需通告多条涉及到的路由条目

4、发送周期性更新、完整路由表更新

参考:距离矢量路由协议与链路状态路由协议

二、基本原理

状态转移方程:table\lbrack i,j\rbrack=\underset{k\in nei\lbrack i\rbrack}{min}(table\lbrack i,j\rbrack,table\lbrack i,k\rbrack+table\lbrack k,j\rbrack)

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函数:路由器每次更新路由表调用的函数

  • 找出相邻的路由,并从它们的路由表更新
  • 从自己的路由表中得到相邻网络的列表,存储在tar中
  • 将tables中存储的每个更新表项和tar中进行比较
  • 若距离是1且目标网络在tar,则将该路由表存储在tables_n
  • tables_n与tar比较再更新
  • 故障处理

原理图:

    #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

猜你喜欢

转载自blog.csdn.net/qq_41747565/article/details/84261298
今日推荐