python实现基于向量算法的的路由协议(RIP)
来源:互联网 发布:网络诋毁公司如何处理 编辑:程序博客网 时间:2024/05/02 02:10
1.实现的功能
- 多个路由器模拟;
- 路由器学习过程日志输出;
- 路由器路由信息输出(查看);
- 模拟网络故障;
- 多线程
- 图形化界面(显示、交互)。
2.算法的简单介绍
算法主要分为两块:GUI界面的实现和向量算法的实现
使用了多线程来让所有路由器一起工作,设置了每个路由器接受更新路由表的时间为1s。
由用户输入每个路由的初始路由表:路由名称和目的网络,距离默认为1(支持1-16的输入,大于16或小于1会提示错误),下一跳默认为空不填(支持填写)。
3.详细说明
一. GUI界面的实现:tkinter
实现了如下界面,包括了路由信息的输入,模拟路由器故障以及保存信息三个模块,使用了Button,Label,Entry,Text,messageBox,filedialog等控件。
界面:
代码片段:
#GUI界面 root = Tk() root.title('基于距离向量算法的路由协议的实现') #左边的输入框 m_l = PanedWindow(showhandle = True, sashrelief = SUNKEN) m_l.pack(fill = BOTH, expand = 1, padx = 10, pady = 10) frame_l = LabelFrame(m_l, text = '输入路由信息:', font = 18, padx = 5, pady = 5) frame_l.pack(padx = 10, pady = 10) Label(frame_l, text = '路由器名称:', font = 16).grid(row = 0, column = 0, sticky = W, pady = 5) Label(frame_l, text = '目的网络:', font = 16).grid(row = 1, column = 0, sticky = W, pady = 5) Label(frame_l, text = '距离:', font = 16).grid(row = 2, column = 0, sticky = W, pady = 5) Label(frame_l, text = '下一跳:', font = 16).grid(row = 3, column = 0, sticky = W, pady = 5) e_name = Entry(frame_l, justify = CENTER) e_name.grid(row = 0, column = 1) e_net_tar = Entry(frame_l, justify = CENTER) e_net_tar.grid(row = 1, column = 1) e_distance = Entry(frame_l, justify = CENTER) e_distance.grid(row = 2, column = 1) e_next_ = Entry(frame_l, justify = CENTER) e_next_.grid(row = 3, column = 1) b_add = Button(frame_l, text = '添加', font = 18, command = lambda : add_callback(tables), padx = 20, pady = 5) b_add.grid(row = 4, column = 0, pady = 5) b_start = Button(frame_l, text = '更新', font = 18, command = lambda : update_callback(tables,table_new), padx = 20, pady = 5) b_start.grid(row = 4, column = 1, pady = 5) Label(frame_l, text = '', font = 16).grid(row = 5, column = 0, sticky = W, pady = 5) Label(frame_l, text = '模拟网络故障:', font = 18).grid(row = 6, column = 0, sticky = W, pady = 5) Label(frame_l, text = '故障路由器名称:', font = 16).grid(row = 7, column = 0, sticky = W, pady = 5) e_name_w = Entry(frame_l, justify = CENTER) e_name_w.grid(row = 7, column = 1) b_w = Button(frame_l, text = '故障', font = 18, command = lambda : wrong_callback(tables), padx = 20, pady = 5) b_w.grid(row = 8, column = 0, pady = 5, columnspan = 2) Label(frame_l, text = '', font = 16).grid(row = 9, column = 0, sticky = W, pady = 5) Label(frame_l, text = '保存信息:', font = 18).grid(row = 10, column = 0, sticky = W, pady = 5) b_save_info = Button(frame_l, text = '保存路由表', font = 16, command = save_info_callback, padx = 10, pady = 5) b_save_info.grid(row = 11, column = 0, pady = 5) b_save_log = Button(frame_l, text = '保存日志', font = 16, command = save_log_callback, padx = 10, pady = 5) b_save_log.grid(row = 11, column = 1, pady = 5) #右边的信息和log m_r = PanedWindow(orient = VERTICAL, showhandle = True, sashrelief = SUNKEN) frame1 = LabelFrame(m_r, text = '路由表信息:', font = 16, padx = 5, pady = 5) frame1.pack(padx = 10, pady = 10) sb1 = Scrollbar(frame1) sb1.pack(side = RIGHT, fill = Y) t1 = Text(frame1, width = 60, height = 20, font = 16, state = DISABLED, yscrollcommand = sb1.set) t1.pack(side = LEFT, fill = BOTH) sb1.config(command = t1.yview) m_r.add(frame1) frame2 = LabelFrame(m_r, text = '日志信息:', font = 16, padx = 5, pady = 5) frame2.pack(padx = 10, pady = 10) sb2 = Scrollbar(frame2) sb2.pack(side = RIGHT, fill = Y) t2 = Text(frame2, width = 60, height = 15, font = 16, state = DISABLED, yscrollcommand = sb2.set) t2.pack(side = LEFT, fill = BOTH) sb2.config(command = t2.yview) m_r.add(frame2) m_l.add(frame_l) m_l.add(m_r) mainloop()
二.函数部分的实现
分为两个部分:实现该协议的函数和控件的callback函数
实现的主要函数的说明
add函数:用户输入一个路由信息,便向路由表的集合中添加一组数据
send函数:路由器每次发送自己的路由表的时候调用的函数
update函数:路由器每次更新路由表调用的函数
threads函数:为每个路由器的发送和更新路由表分配线程控件的callback函数说明
(1)add_callback函数:点击添加按钮时调用的函数,在函数中调用了 add函数
(2)update_callback函数:用户点击更新按钮时调用的函数,在函数中调用了threads函数
(3)wrong_callback函数:用户点击故障按钮时的调用的函数,在函数中将路由表的集合中的故障路由的表项去掉
(4)save_info_callback&save_log_callbac函数:用户点击保存路由表/保存日志按钮时调用的函数,用于将信息以文本形式输出
三. 主要算法思想
update函数:这里实现了路由表的更新操作。假设每个路由器不知道相邻路由器的名称,只知道相邻的网络,则路由器发送路由表是以广播的形式,我用tables这个列表储存所有更新路由表的集合。
(1)首先需要找出相邻的路由,并从他们的路由表中得到更新表
先从自己的路由表中得到相邻网络的列表,存储在tar中。
(2)然后将tables中存储的每个更新表的项和tar中的进行比较,如果距离是1且目标网络在tar中,则将该路由的表存储在tables_n中。接着将tables_n中的项依次与本路由表的项进行比较(见下面的流程图) 。最后一步就是对故障的处理,如果有故障的路由,则将以故障路由为下一跳的所有项的距离设置为不可达(16)。
代码片段:
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]: 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[2] == luyou_wrong: i[1] = 16 lock.acquire() table_new.append(table_n) lock.release()
**
4.测试结果
**
1. 输入一条信息,并点击添加
**
如果输入的距离不是1-16的数字(浮点数会舍去小数部分),会提示错误,比如输入字母或者大于16或小于1的数字
我们按照NET5-A-NET1-B-NET2-C-NET3-D-NET4-E-NET5的拓扑结构输入信息
2.点击更新,分别看一下路由表信息和日志信息:
路由表信息会记录每一次的历史路由表信息日志
日志信息则会记录下每一次添加表项 ,更新表项的结果
第一次更新之后,每个路由表变成了四项,我们再点击一次更新
现在每个路由器变成了5项,且表项也都正确。
(3)我们让A路由器故障
再次点击更新
我们看到下一跳为A的路由表项的距离都变成了16(不可达)
(4)我们点击保存路由表
我们保存到了桌面的’路由表.txt’中,找到并打开查看,发现路由信息已经保存进去了。
保存日志类似。
5.代码分享
**
from tkinter import *import threading,time,copy,os#全局变量lock = threading.Lock() #进程锁tables = [] #网络上的路由表的集合table_new = [] #更新后的路由表的集合 #通过这两个表的交换赋值来更新luyou_wrong = '--' #故障的表的名字(默认一次只能故障一个路由)#每次更新控件显示的字符串str_send = '' #发送了自己路由表的信息str_update = '' #更新了自己路由表的信息def time_now():#用于获得当前时间 return str(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()))def main():#主函数 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 def send(table):#向相邻网络发送自己的路由表 string = table[0] + '向相邻路由发送了自己的路由表 ' global str_send str_send += time_now() + '\n' + string + '\n' 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() 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 def log(string):#更新日志的函数 string = time_now() + '\n' + string + '\n' t2.config(state = NORMAL) t2.insert(INSERT,string) t2.see(END) t2.config(state = DISABLED) def show_add(tables):#用户添加初始路由表时更新路由信息 string = '' string += '--------------------------------------------------\n' string += '更新时间:' + str(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())) + '\n' for each in tables: string += '路由器' + each[0]+':\n' for i in range(len(each[1])): string += '('+str(i+1) + ')' + ' 目标网络:'+ each[1][i][0] + ' 距离:'+ str(each[1][i][1]) + ' 下一跳:' + each[1][i][2] + '\n' t1.config(state = NORMAL) t1.delete(1.0,END) t1.insert(INSERT,string) t1.see(END) t1.config(state = DISABLED) def show_up(tables):#每次更新路由表时更新路由信息 string = '' string += '--------------------------------------------------\n' string += '更新时间:' + str(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())) + '\n' for each in tables: string += '路由器' + each[0]+':\n' for i in range(len(each[1])): string += '('+str(i+1) + ')' + ' 目标网络:'+ each[1][i][0] + ' 距离:'+ str(each[1][i][1]) + ' 下一跳:' + each[1][i][2] + '\n' t1.config(state = NORMAL) t1.insert(INSERT,string) t1.see(END) t1.config(state = DISABLED) #控件的callback函数 def add_callback(tables):#添加按钮 distance = e_distance.get() if distance.isdigit(): name = e_name.get() net_tar = e_net_tar.get() next_ = e_next_.get() if name != '' and net_tar != '' and distance != '': distance = int(distance) if distance>=1 and distance<=16: data = [name,net_tar,distance,next_] tables = add(data,tables) show_add(tables) else: messagebox.showinfo('警告','距离应当为1-16的整数!') else: messagebox.showinfo('警告','路由器名称,目标网络和距离不能为空!') else: messagebox.showinfo('警告','距离应当为1-16的整数!') def update_callback(tables,table_new):#更新按钮 table_new.clear() tables_n = threads(tables,table_new) tables.clear() tables.extend(tables_n) show_up(tables) return tables def wrong_callback(tables):#故障按钮 global luyou_wrong name_w = e_name_w.get() if name_w == '': messagebox.showinfo('警告','故障网络名称不能为空!') else: luyou_wrong = name_w messagebox.showinfo('通知','网络%s已设置为故障!' % name_w) t2.config(state = NORMAL) t2.insert(INSERT, '网络%s故障!' % name_w) t2.see(END) t2.config(state = DISABLED) def save_info_callback():#保存路由信息 if not t1.get(1.0,END).isspace(): file = filedialog.asksaveasfilename(defaultextension = '.txt', filetypes = [('txt,TXT','.txt'),('ALL','.*')]) os.chdir(os.path.dirname(file)) f = open(os.path.basename(file),'w') f.write(t1.get(1.0,END)) f.close() messagebox.showinfo('通知','路由表信息已保存在%s中!' % file) else: messagebox.showinfo('警告','路由表信息为空!') def save_log_callback():#保存日志信息 if not t2.get(1.0,END).isspace(): file = filedialog.asksaveasfilename(defaultextension = '.txt', filetypes = [('txt,TXT','.txt'),('ALL','.*')]) os.chdir(os.path.dirname(file)) f = open(os.path.basename(file),'w') f.write(t2.get(1.0,END)) f.close() messagebox.showinfo('通知','日志信息已保存在%s中!' % file) else: messagebox.showinfo('警告','路由表信息为空!') #GUI界面 root = Tk() root.title('基于距离向量算法的路由协议的实现') #左边的输入框 m_l = PanedWindow(showhandle = True, sashrelief = SUNKEN) m_l.pack(fill = BOTH, expand = 1, padx = 10, pady = 10) frame_l = LabelFrame(m_l, text = '输入路由信息:', font = 18, padx = 5, pady = 5) frame_l.pack(padx = 10, pady = 10) Label(frame_l, text = '路由器名称:', font = 16).grid(row = 0, column = 0, sticky = W, pady = 5) Label(frame_l, text = '目的网络:', font = 16).grid(row = 1, column = 0, sticky = W, pady = 5) Label(frame_l, text = '距离:', font = 16).grid(row = 2, column = 0, sticky = W, pady = 5) Label(frame_l, text = '下一跳:', font = 16).grid(row = 3, column = 0, sticky = W, pady = 5) e_name = Entry(frame_l, justify = CENTER) e_name.grid(row = 0, column = 1) e_net_tar = Entry(frame_l, justify = CENTER) e_net_tar.grid(row = 1, column = 1) e_distance = Entry(frame_l, justify = CENTER) e_distance.grid(row = 2, column = 1) e_next_ = Entry(frame_l, justify = CENTER) e_next_.grid(row = 3, column = 1) b_add = Button(frame_l, text = '添加', font = 18, command = lambda : add_callback(tables), padx = 20, pady = 5) b_add.grid(row = 4, column = 0, pady = 5) b_start = Button(frame_l, text = '更新', font = 18, command = lambda : update_callback(tables,table_new), padx = 20, pady = 5) b_start.grid(row = 4, column = 1, pady = 5) Label(frame_l, text = '', font = 16).grid(row = 5, column = 0, sticky = W, pady = 5) Label(frame_l, text = '模拟网络故障:', font = 18).grid(row = 6, column = 0, sticky = W, pady = 5) Label(frame_l, text = '故障网络名称:', font = 16).grid(row = 7, column = 0, sticky = W, pady = 5) e_name_w = Entry(frame_l, justify = CENTER) e_name_w.grid(row = 7, column = 1) b_w = Button(frame_l, text = '故障', font = 18, command = lambda : wrong_callback(tables), padx = 20, pady = 5) b_w.grid(row = 8, column = 0, pady = 5, columnspan = 2) Label(frame_l, text = '', font = 16).grid(row = 9, column = 0, sticky = W, pady = 5) Label(frame_l, text = '保存信息:', font = 18).grid(row = 10, column = 0, sticky = W, pady = 5) b_save_info = Button(frame_l, text = '保存路由表', font = 16, command = save_info_callback, padx = 10, pady = 5) b_save_info.grid(row = 11, column = 0, pady = 5) b_save_log = Button(frame_l, text = '保存日志', font = 16, command = save_log_callback, padx = 10, pady = 5) b_save_log.grid(row = 11, column = 1, pady = 5) #右边的信息和log m_r = PanedWindow(orient = VERTICAL, showhandle = True, sashrelief = SUNKEN) frame1 = LabelFrame(m_r, text = '路由表信息:', font = 16, padx = 5, pady = 5) frame1.pack(padx = 10, pady = 10) sb1 = Scrollbar(frame1) sb1.pack(side = RIGHT, fill = Y) t1 = Text(frame1, width = 60, height = 20, font = 16, state = DISABLED, yscrollcommand = sb1.set) t1.pack(side = LEFT, fill = BOTH) sb1.config(command = t1.yview) m_r.add(frame1) frame2 = LabelFrame(m_r, text = '日志信息:', font = 16, padx = 5, pady = 5) frame2.pack(padx = 10, pady = 10) sb2 = Scrollbar(frame2) sb2.pack(side = RIGHT, fill = Y) t2 = Text(frame2, width = 60, height = 15, font = 16, state = DISABLED, yscrollcommand = sb2.set) t2.pack(side = LEFT, fill = BOTH) sb2.config(command = t2.yview) m_r.add(frame2) m_l.add(frame_l) m_l.add(m_r) mainloop()if __name__=='__main__': main()
- python实现基于向量算法的的路由协议(RIP)
- RIP协议的距离向量算法--C++
- RIP路由表调整算法的实现
- RIP路由协议的理解
- java实现基于距离向量算法 路由协议
- 【RIP路由协议】由相邻路由发来的RIP信息更新当前路由的路由表
- 对RIP动态路由协议的攻击
- RIP和IGRP路由协议的配置
- 动态路由协议的基本配置---RIP
- RIP动态路由协议的配置命令
- 路由动态协议RIP协议的路由环路及解决办法
- 实现rip路由选择协议
- 内部网关协议RIP 距离向量算法
- RIP协议与向量距离算法
- 课程设计RIP协议路由表调整算法
- RIP协议V-D算法的介绍
- RIP协议V-D算法的介绍
- 13、RIP协议的概念及算法
- 使用npm安装一些包失败了的看过来(npm国内镜像介绍),亲测可用,非常吊!
- 【FontsManager】安卓一行代码实现自定义字体替换
- 第一次程序慢
- 开发中常见问题与特殊问题记录
- 洛谷 2672
- python实现基于向量算法的的路由协议(RIP)
- 文件的压缩与打包
- LightOJ-1058-math
- app.gradle中配置打包秘钥
- newScheduledThreadPool延时任务线程池,实现原理
- 参考文献对齐的设置方法
- 一天一条Linux指令-declare
- BZOJ1001: [BeiJing2006]狼抓兔子
- 今天开通了CSDN博客~