本人
如果学院那边改了project内容的话,估计这篇文章也不会有人看了。
如果还有人看,啊挪,最好是思考了之后再来看这篇文章。
先放福利:点我点我
这个project可能会比较重要,所以我会讲的详细些(自我感觉,甚至过于详细)。

项目内容如下:

1、用Kruskal算法给给定的网络计算一棵最小生成树;

2、用计算出的最小生成树完成广播业务;

3、将业务可视化展示。

网络如下:(数据都是助教大大给的。数据改变或拓扑结构改变的话,生成树可能会变。之后的project都会以这个网络为例。学院那边肯定会给你个更加复杂的拓扑,但是,这个例子懂了的fa,不管网络怎么变,只要过程没问题的话,结果还会是我们想要的)

7个结点

我们当时做project真正用到的是24个结点的。

24结点

上面那个网络中,每个交换机(switch)下面只下挂一个主机(host)哦。

网络知道了,怎么让Mininet创建了这个网络呢?

答一:B站是个学习网站。参考https://www.bilibili.com/video/BV1hT4y1374f。(视频里面小姐姐的声音好好听)答二:什么你不喜欢这样拉?因为太麻烦了?emmm......还是看上面那个链接的视频,只要看懂这样拉来拉去之后,miniedit会创建出怎么样的py文件,然后根据创建出来的py文件中代码的格式进行自主的删减就行了。答三:什么,你觉得上面的回答都不够帅气?代码量贼大贼麻烦??emmm......回忆一下当年的C/C++实验,我们是怎么拉取某个文件里面的信息的?以此类推,给实验的网络创建一个json文件,里面记录该网络的拓扑信息。大致长这样:


然后写一个可以拉取json文件的mininet创建网络脚本(我管它叫tp777.py)。

from mininet.topo import Topo
from collections import Counter
from mininet.link import TCLink
from mininet.log import setLogLevel
import os
import json
from mininet.net import Mininetclass Tp777(Topo):def __init__(self):Topo.__init__(self)topoinfo=json.load(open('./topo7.json','r',encoding='utf-8-sig'))num_host=topoinfo["host_no"]num_switch=topoinfo["switch_no"]link_list=topoinfo["links"]for h in range(1,num_host+1):self.addHost('h'+str(h))for s in range(1,num_switch+1):self.addSwitch('s'+str(s))for link in link_list:v=link["vertexs"]d=link["delay"]b=link["bw"]self.addLink(v[0],v[1],delay=str(d)+'ms',bw=b)
topos={'mytopo':(lambda:Tp777())}

相信后浪们都懂上面写了啥。这个py文件要和对应的json放在一起哦。

json敲完了,py敲完了,文件怎么启动呢,阿巴阿巴。在tp777.py目录下叫出终端,然后

sudo mn --custom tp777.py --topo=mytopo --controller=remote,ip=127.0.0.1,port=6653 --mac

Mininet那边搞完了,开始搞Ryu的。

编写Ryu控制器逻辑脚本

学习那么久了,先看个视频放松放松吧。https://www.bilibili.com/video/BV1VJ41117vJ?p=17

照着敲一遍估计能大概了解Ryu是怎么工作的了。

如果俺没记错,上面那个视频中up主是把网络放在networkx中然后用networkx中的最短路算法。这个项目中我们也会用到networkx,但是仅仅只是用到它的可视化功能,不会使用到它自带的算法(u1s1,这样做助教肯定喂你吃鸡蛋,虽然视频没有错)

先告诉Ryu我们的网络长啥样。

这一步可以手敲二维列表来存网络:

也可以借鉴之前的方法,通过拉取json文件中的信息来存储网络信息:

self.Matrix就是用来存网络信息的二维列表。
之后编写Kruskal算法。这一步相信老师讲过,网上也有很多资料,这部分就不多说了。

上面所说的都是偏理论的部分,但是怎么把这些理论落实到仿真网络上面呢?

参考我之前分享的那个讲Ryu的视频。该视频讲到的

都不用修改。紫玛里,事件SwitchEnter和PachetIn是需要我们改写的。

SwitchEnter在检测到交换机加入时触发行为。那么,有人可能会问了,MIKU她老公呀,到底触发甚么行为了?

刚刚那个视频里面在这个事件下所做的事是拉取网络中的链路信息。其中我认为最重要的信息是端口信息,就是某个交换机是用哪个端口和另几台交换机连接的。除此之外,为了完成这个project我们还需在这个事件下调用我们刚刚写好的Kruskal算法(Kruskal算法所用到的网络信息通过json文件拉取)。Kruskal算法结束后,使用networkx的可视化功能画图(画图功能实现可以参考文章一开始的“福利”)。

下面写PacketIn事件下的行为。在SDN中交换机在没有对应流表项的时候,交换机会把接收到的数据包递给控制器,让控制器根据上传上来的包的信息给交换机下发对应的流表,这样交换机才知道这个数据包应该怎么走。他们的“对话”(该内容纯属虚构,如有雷同,纯属转生到了异世界)大致如下:

一号交换机:阿巴阿巴阿巴阿巴,嗯?!从西面飞来了一个包裹,让我看看哈,发送地址22号主机,目的地址33号主机。懵…不认识啊,33号主机在哪呀?交给控制器大佬,他肯定知道的。

控制器:哦,原来是佐田是33啊。根据我刚刚算出来的MST,你这个包应该交给你的西北面那个交换机。记住哦,以后收到这个目的地址的包都要这样做哦。

一号交换机:哇嘎哒!

之前不是在SwitchEnter里面算出了最小生成树和知道了网络中交换机之间的连接端口了吗。那么只要我们根据MST的信息,不就是可以知道某个交换机的哪些端口能用,哪些不能用了嘛。所以我们命令交换机,把收到的数据包,往所有没有被禁止使用的端口发送(数据包的入端口也算在本次行为的禁止端口中哦,不然数据包又回到之前的地方,这不就成环了嘛)

嗯?mouse写完了。那就运行一下吧。


也许你注意到了,打印出来的路径,怎么会有些是缺失了的?原因在于我们下发的流表所包含的信息不够多——里面只描述了是这个目的地址就应该这么走。但是如果我们把源地址也写进流表,打印的路径就不会缺失啦(这部分就交给聪明的你来写了)。

一些我遇到的坑:

1)Ryu逻辑文件放在桌面然后运行时候报错说,没有找到这个py文件:

把这个py文件放在这里试试

还是不行的话参考百度里面的其余做法。

2)怎么老是有这个报错?

1、是不是哪里多了或少了括号,冒号?多了分号?
2、多了或少了空格?多了或少了Tab?Python对缩进要求很高的哦。建议在你的文本编写器中开启空格与制表的可视化。

3)为什么拉取到的端口信息会缺失?

试试在SwitchEnter事件中加入sleep,并调试sleep的参数。

参考资料:

https://blog.csdn.net/qq_43734019/article/details/104334722?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-6&spm=1001.2101.3001.4242

https://www.bilibili.com/video/BV1hT4y1374f

https://www.bilibili.com/video/BV1VJ41117vJ?p=17

附录:

部分代码参考文章一开始的“福利”。

# encoding:utf-8
from ryu.base import app_manager
from ryu.ofproto import ofproto_v1_3
from ryu.controller.handler import set_ev_cls
from ryu.controller import ofp_event
from ryu.controller.handler import CONFIG_DISPATCHER,MAIN_DISPATCHER
from ryu.lib.packet import packet
from ryu.lib.packet import ethernet
from ryu.topology import event
from ryu.topology.api import get_switch,get_link
import numpy as np
import networkx as nx
import matplotlib.pyplot as plt
from collections import defaultdict
import time
import string
import jsonclass Topo(object):                                                     # algorithmdef __init__(self,logger):self.Matrix = np.array(np.ones((7,7))*999999)self.host_to_switch = np.array(np.ones((7,1))*8848)self.logger=loggerdef get_graph(self):topoinfo=json.load(open('./topo7.json','r'))link_list=topoinfo["links"]for link in link_list:                                          # get delay info and build a matrix to store delay infov=link["vertexs"]d=link["delay"]if v[0][0]=='s' and v[1][0]=='s':self.Matrix[int(v[0][1])-1][int(v[1][1])-1] = dself.Matrix[int(v[1][1])-1][int(v[0][1])-1] = dif v[0][0] == 'h':self.host_to_switch[int(v[0][1])-1] = dreturn self.Matrixdef get_nodenum(self,Matrix):return len(Matrix)def get_edgenum(self,Matrix):count = 0for j in range(len(Matrix)):for i in range(j):if Matrix[i][j] > 0 and Matrix[i][j] < 999999:count += 1return countdef kruskal(self, Matrix):#get basic info of the matrix,which contains the topologynodenum = self.get_nodenum(Matrix)edgenum = self.get_edgenum(Matrix)#result_list contains the edges (node1,node2,info of delay) on the mstresult_list = []if nodenum <= 0 or edgenum < nodenum - 1:return result_list#however they are not sortededge_list = []for i in range(nodenum):for j in range(i+1, nodenum):#the info of delay != 999999 means it is an edge in the topoif Matrix[i][j] < 999999:#(s1,s2,weight)edge_list.append([i, j, Matrix[i][j]])# sort by comparing the info of delayedge_list.sort(key=lambda a: a[2])a = [[i] for i in range(nodenum)]# to make sure the edge in result_list cannot build a loopfor edge in edge_list:for i in range(len(a)):if edge[0] in a[i]:m = iif edge[1] in a[i]:n = iif m != n:result_list.append(edge)a[m] = a[m] + a[n]a[n] = []return result_list#if we have edge(0,1) and (0,2) then links[0] = [1,2]def comput_tree(self,src,result_list):                              # it returns adj-nodeslist1 = result_listlinks = [[] for i in range(len(result_list) + 1)]for i in range(len(result_list) + 1):for edge in list1:if i == edge[0]:links[i].append(edge[1])elif i == edge[1]:links[i].append(edge[0])return links#it returns a list which cotains (previous node, node here we are, an adjacent node)def compute_links(self,src,pre_src,links):result = []if len(links[src]) < 1:return resultfor node in links[src]:if node != pre_src:result.append((pre_src,src,node))newresult = self.compute_links(node,src,links)          # recursionresult.extend(newresult)return result# in this part we want to figure out which next switch is#result from compute_linksdef compute_next_switch(self,result):next_switch = []for i in range(7):for j in range(6):if result[j][1] == i:k = result[j][2]next_switch.append((i+1,k+1))return next_switchclass KruskalTwo(app_manager.RyuApp):                                   # eventOFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]def __init__(self, *args, **kwargs):super (KruskalTwo, self).__init__(*args, **kwargs)self.mac_to_port = {}self.network = nx.DiGraph()self.topology_api_app = selfself.paths = {}self.topo = Topo(self.logger)self.isKruskal_done = Falseself.Matrix = np.array(np.ones((7,7))*999999)self.linkList1 = []self.links_node2node = []self.next_switch  = []self.tree = [[] for i in range(7)]                   #if we have edge(0,1) and (0,2) then links[0] = [1,2]self.port_can_be_used = [[] for i in range(7)]self.count1 = 0self.all_port = [[] for i in range(7)]self.forbidden_port = [[] for i in range(7)]self.passerby = {}# handle switch features info@set_ev_cls(ofp_event.EventOFPSwitchFeatures,CONFIG_DISPATCHER)def switch_features_handler(self,ev):datapath = ev.msg.datapathofproto = datapath.ofprotoofp_parser = datapath.ofproto_parser# install a table-miss flow entry for each datapathmatch = ofp_parser.OFPMatch()actions = [ofp_parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,ofproto.OFPCML_NO_BUFFER)]self.add_flow(datapath,0,match,actions)def add_flow(self,datapath,priority,match,actions):ofproto = datapath.ofprotoofp_parser = datapath.ofproto_parser# construct a flow_mod msg and send it to datapathinst = [ofp_parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,actions)]mod = ofp_parser.OFPFlowMod(datapath=datapath,priority=priority,match=match,instructions=inst)datapath.send_msg(mod)# get topology and store topology info into networkx@set_ev_cls(event.EventSwitchEnter,[CONFIG_DISPATCHER,MAIN_DISPATCHER])     ## whlie a switch enters the netdef get_topology(self,ev):# get links and add links      now we can know that ,for example,src is 1, dst is 2, the port.no is the port in src that packet should get out# get outportslinks_list = get_link(self.topology_api_app,None)                               ### !!!!!!!!!links = [(link.src.dpid,link.dst.dpid,link.src.port_no) for link in links_list] ### !!!!!!!!!#  print('links:',links)#    self.network.add_edges_from(links)# print('tree:',self.tree)if self.isKruskal_done == False:                            # the function in Topo should be done once then store all resultself.Matrix = self.topo.get_graph()self.linkList1 = self.topo.kruskal(self.Matrix)print 'edges on the tree:',self.linkList1self.tree = self.topo.comput_tree(1-1,self.linkList1)print 'adj-switch:',self.treeprint 'please wait......'                                    # adj-switchself.links_node2node = self.topo.compute_links(1-1,None,self.tree)# print('links_node2node:',links_node2node)self.next_switch = self.topo.compute_next_switch(self.links_node2node)    # next_switch has 23 edges#   print('next_switch:',self.next_switch)                      # this is a list containing you-fang-xiang-de-edgesself.isKruskal_done = True# in self.tree we get nodes' adj-nodes that in the tree, by using this message#and links = [(link.src.dpid,link.dst.dpid,link.src.port_no) for link in links_list] , we can know the ports usedport_can_be_used = [[] for i in range(7)]all_port = [[] for i in range(7)]for m in range(7):for s in range(len(links)):if links[s][0] == m+1:for t in range(len(self.tree[m])):if links[s][1] == 1+self.tree[m][t]:port_can_be_used[m].append(links[s][2])#    print('port_can_be_used:',port_can_be_used)for m in range(7):for s in range(len(links)):if links[s][0] == m+1:all_port[m].append(links[s][2])self.count1 = self.count1+1if self.count1 == 7:self.port_can_be_used = port_can_be_usedself.all_port = all_portfor m in range(7):for t in self.all_port[m]:if t not in self.port_can_be_used[m]:self.forbidden_port[m].append(t)print 'self.forbidden_port:',self.forbidden_portprint 'Exit the networkx, if you would like to go on.'#drawG=nx.Graph()weight={}graph=[]for i in range(len(self.Matrix)):for j in range(i):if self.Matrix[i][j] > 0 and self.Matrix[i][j] < 999999:graph.append((i+1,j+1))graph.append((j+1,i+1))weight[(i+1,j+1)]=self.Matrix[i][j]weight[(j+1,i+1)]=self.Matrix[i][j]path=[]for link1 in self.linkList1:path.append((link1[0]+1,link1[1]+1))path.append((link1[1]+1,link1[0]+1))for gra in graph:G.add_edge(gra[0],gra[1],color='black')for pat in path:G.add_edge(pat[0],pat[1],color='r')pos=nx.spring_layout(G)edges = G.edges()colors = [G[u][v]['color'] for u,v in edges]nx.draw_networkx_nodes(G,pos,node_size=233)nx.draw_networkx_edges(G,pos,width=3,edge_color=colors)nx.draw_networkx_labels(G,pos,font_size=10)nx.draw_networkx_edge_labels(G,pos,weight,font_size=10)plt.show()#draw endprint 'Done!'time.sleep(1.0)                                                 #mininet's add_nodes and add_links are not that fast,this function runs only if a switch enters,we may finish this function when all#links have not been added# handle packet_in msg@set_ev_cls(ofp_event.EventOFPPacketIn,MAIN_DISPATCHER)def packet_in_handler(self,ev):msg = ev.msgdatapath = msg.datapathofproto = datapath.ofprotoofp_parser = datapath.ofproto_parserdpid = datapath.idself.mac_to_port.setdefault(dpid,{})pkt = packet.Packet(msg.data)eth = pkt.get_protocol(ethernet.ethernet)dst = eth.dstsrc = eth.src#    print srcin_port = msg.match['in_port']self.mac_to_port[dpid][src] = in_port#   print('mac_to_port',self.mac_to_port)if dst in self.mac_to_port[dpid]:out_port = self.mac_to_port[dpid][dst]actions = [ofp_parser.OFPActionOutput(out_port)]match = ofp_parser.OFPMatch(in_port=in_port,eth_dst=dst)self.add_flow(datapath,1,match,actions)self.passerby.setdefault(src,{})self.passerby[src].setdefault(dst,[])self.passerby[src][dst].append(dpid)print("from h{} to h{}".format(int(src.split(':')[-1],16),int(dst.split(':')[-1],16)))print 'switches passed by:',self.passerby[src][dst]        #why sometimes the switches passby do not be printed?because#the switches have been installed flow ,they donot have to#ask the controller, and the event won't happen# print('mac_to_port',self.mac_to_port[dpid])else:      #floodactions = []for i in datapath.ports:if ((i not in self.forbidden_port[dpid-1]) and (i != in_port)):actions.append(ofp_parser.OFPActionOutput(i))out = ofp_parser.OFPPacketOut(datapath=datapath,buffer_id=ofproto.OFP_NO_BUFFER,in_port=in_port,actions=actions,data=msg.data)datapath.send_msg(out)

通信网实验_Kruskal算法_Mininet_Ryu相关推荐

  1. 通信网实验_DFS算法_Dijkstra算法_Mininet_Ryu

    这两个project的实现需要广播,也就是需要以https://www.bilibili.com/read/cv9546894为基础. 为什么这两实验需要广播?因为要做链路层发现,洪泛的时候要用到MS ...

  2. Java1.使用二分搜索算法查找任意N个有序数列中的指定元素。 2.通过上机实验进行算法实现。 3.保存和打印出程序的运行结果,并结合程序进行分析,上交实验报告。 4.至少使用两种方法进行编程,直接查

    1.使用二分搜索算法查找任意N个有序数列中的指定元素. 2.通过上机实验进行算法实现. 3.保存和打印出程序的运行结果,并结合程序进行分析,上交实验报告. 4.至少使用两种方法进行编程,直接查找/递归 ...

  3. 自然语言处理实验—分词算法(含python代码及详细例子讲解)

    自然语言处理实验-分词算法 最近在学自然语言处理,这是第一个上机实验自然语言处理的分词算法,也是自然语言处理比较入门的算法.和大家分享一下. 首先,自然语言处理,英文是(Nature Language ...

  4. 算法设计与分析 实验五 算法综合实验

    实验5.<算法综合实验> 一.实验目的 理解和复习所学各种算法的概念 掌握和复习所学各种算法的基本要素 掌握各种算法的优点和区别 通过应用范例掌握选择最佳算法的设计技巧与策略 二.实验内 ...

  5. 语法分析实验ll算法c语言,实验5LL语法分析程序的设计与实现(C语言).doc

    实验5LL语法分析程序的设计与实现(C语言) 实验五 LL(1)文法识别程序设计 一.实验目的 通过LL(1)文法识别程序的设计理解自顶向下的语法分析思想. E+T|T TT*F|F Fi|(E) 参 ...

  6. 计算机操作系统实验银行家算法,实验六 银行家算法(下)

    实验六 银行家算法(下) 一.实验说明 实验说明:本次实验主要是对银行家算法进行进一步的实践学习,掌握银行家算法的整体流程,理解程序测试时每一步的当前状态,能对当前的资源分配进行预判断. 二.实验要求 ...

  7. 格雷码算法c语言实验报告,算法设计与分析实验报告

    本科生实验报告 课程名称:算法设计与分析 实验项目:递归和分治算法 实验地点:计算机系实验楼110 专业课:物联网1601学生.2016002105 学生姓名:于 指导员:郝晓丽 2018年5月4日 ...

  8. 强化学习 蒲丰投针实验 蒙特卡洛算法

    目录 一.蒲丰投针实验 1.1背景故事 1.2原理介绍 二.蒙特卡洛方法 2.1方法介绍 2.2经验轨迹 2.3在线学习与离线学习 2.4数学原理 一.蒲丰投针实验 1.1背景故事 1777年,蒲丰请 ...

  9. 密码学实验-RSA算法的几种攻击方法的实现

    目录 一.实验要求 (一) RSA算法攻击方法分析相关要求 二.代码简述 (一)费马方法 1.原理: 2.代码分析 (二)pollard rho 方法 1.原理 2.代码分析: (二)pollard ...

  10. 【学习机器学习】实验——聚类算法性能度量

    聚类算法性能度量 前言 一.实验目的 二.实验内容 1.变量a,b,c,d 2.Jaccard系数 3.闵可夫斯基距离 4.avg,diam,dmin,dcen,DB指数 4.1 avg(C) 4.2 ...

最新文章

  1. lisp协议instand_分享|Linux 上 10 个最好的 Markdown 编辑器
  2. 7000 字 23 张图,Pandas一键生成炫酷的动态交互式图表
  3. ubuntu下解压和压缩命令
  4. AOP—JVM SandBox—底层原理解析
  5. Redis 学习笔记-NoSQL数据库 常用五大数据类型 Redis配置文件介绍 Redis的发布和订阅 Redis_事务_锁机制_秒杀 Redis应用问题解决 分布式锁
  6. 常用JavaScript的高级技巧
  7. linux 关联数组,linux 普通数组和关联数组
  8. c语言变量命名规则_带你学习C语言—变量
  9. C# CollectionBase,ICloneeable
  10. C++头文件中定义全局变量在多次引用时出现变量多次定义符号冲突的解决办法...
  11. tp801单板微型计算机是什么,给TP801单板机配接RX—80打印机
  12. Powershell管理系列(一)Active Direcrtory管理:用户管理
  13. 配置 mysql/mariadb sphinxSE 错误解决 1st column must be bigint to accept 64-bit DOCID
  14. C#播放视频时与暴风影音冲突的问题
  15. 京东羚珑页面可视化平台介绍
  16. 【网页设计大作业】:端午主题(HTML+CSS+JavaScript)——中国传统文化(6页)
  17. 基于Ogre1.9开发的3D场景编辑器
  18. thinkphp 3.2引入第三方类
  19. 移动2班徐斌1803230241
  20. windows密码到期_如何在Windows 10中设置密码到期日期

热门文章

  1. android实现矩形,android圆角矩形的实现
  2. Win10系统文件名太长导致无法删除
  3. 0基础学软件测试工程师好学吗?
  4. 【敏捷团队】7.敏捷最后冲刺
  5. 华为服务器jbod修改启动项,服务器设置jbod
  6. 超详细的Android APP 集成 PayPal 境外支付 信用卡 借记卡 支付,支付宝 微信海外 境外支付
  7. 三位数除以两位数竖式计算没有余数_三位数除以两位数有余数竖式运算300题
  8. 网页视频怎么录制?这两个方法操作简单,录制高清!
  9. linux usr目录权限不够,linux-mkdir:无法创建目录“ /usr/local/n / versions”:权限被拒绝...
  10. Matlab同步脉冲触发器参数,脉冲参数有哪些?脉冲参数介绍