Github: https://github.com/Joilence/n...

路由模拟项目介绍

链路状态协议(Link-state routing protocol)和距离向量路由协议(distance-vector routing protocol)是分组交换(Packet switching)网络中最主要的两种路由协议。本项目的模拟路由器实现了LS路由算法、LS广播洪泛、DV路由算法,以及防止DV路由环路和无穷计数问题的策略。此外还实现了完整的前后端以便研究者通过UI界面自定义网络拓扑、控制路由器、查看路由器信息和日志。

链路状态算法(LS)

LS算法要求网络中每个节点都收集完整的网络信息,以邻接表的形式存储整个网络的拓扑结构和所有链路的费用,然后根据这个图来运行路由选择算法(在这里我们选择Dijkstra算法),计算出从本节点到网络中所有其他节点的最低费用路径。

LS广播

为了让每个节点都知道整个网络的拓扑结构和所有链路费用,每个节点都要将自己直连的链路信息广播给网络中的所有节点(LS广播)。要广播的信息包括自己的邻居有哪些、到达它们的链路开销分别是多少。

为了更新它本身存储的网络拓扑图,在接收到其他节点的LS广播时,要根据广播中的链路信息更新自己的邻接表。

同时,在接收到其他节点的LS广播时,要将它转发给自己的所有邻居,从而这个LS广播能散播到整个网络。为了避免广播风暴(广播包在网络中无休止地传播,导致网络瘫痪),每个路由器要辨别接收到的LS广播包是不是已经接收过。这可以通过一个广播包中的序列号字段来做到。每台ls路由器,每次广播使用一个递增的序列号,如果多次收到来自同一台路由器且序号相同的广播,则不更新邻接表,也不转发给邻居,防止广播风暴。

迪杰斯特拉算法(Dijkstra's algorithm)

Dijkstra算法能够计算出图中所有节点到某个节点的最短路径。对于一个图和一个给定的原点,Dijkstra算法不断选择一个距离源点最近且尚未扩展的节点w来扩展,并更新w的邻居节点到原点的距离。最终,所有被扩展的节点就是从原点可以到达的节点,它们被扩展时到原点的距离就是最终的最短距离。

什么时候触发Dijkstra算法计算出新的路由表

Dijkstra算法的输入就是节点维护的邻接表,因此只要邻接表有更新,就要触发Dijkstra算法计算出新的路由表。
那么邻接表什么时候会更新呢?有2种情况:

  1. 本节点的直连链路发生变化,要更新邻接表中对应的链路。
  2. 接收到新的LS广播,要根据LS广播中的信息更新邻接表。

距离向量算法(DV)

DV算法不需要全局网络信息。每个节点只从直连邻居接收路由通告,执行DV计算,然后将计算结果分发给直连邻居。重复这个过程,直到每个节点的DV计算结果都与上一次的DV计算结果相同,此时网络中不再有路由通告,算法终止。

DV算法

DV算法的思想相对比较简单:邻居能到达的节点,我经过这个邻居也能到达,并且我去目标节点的费用 = 我到邻居的费用 + 邻居到目标节点的费用。一个节点的DV存储的就是这个节点能到达哪些节点、费用分别是多少。

DV算法的输入是所有邻居的DV和自己的直连链路信息,输出是自己的DV(也就是路由表)。如果输出的DV与上次输出的不同,也就是自己的DV发生了变化,那么要将自己的DV通告给所有邻居。

有几点需要注意:

  1. 为了保证DV算法的自我终止(网络中不再有DV通告,也不再运行DV算法),仅仅当DV发生变化时才通告给邻居。
  2. DV的计算完全不依赖于自己上次计算得到的DV(也就是自己当前的路由表)。

路由环路和无穷计数问题

由于DV算法没有全局网络信息,DV算法中可能会出现路由环路和无穷计数的问题。

The Bellman–Ford algorithm does not prevent routing loops from happening and suffers from the count-to-infinity problem. The core of the count-to-infinity problem is that if A tells B that it has a path somewhere,there is no way for B to kNow if the path has B as a part of it.
如果A告诉B:A能到达C。由于B没有全局网络信息,它无法知道自己是否已经处于从A到C的路径上。
https://en.wikipedia.org/wiki...

为了避免路由环路和无穷计数,我们使用了Split-horizon routing with poison reverse和Holddown的策略。详见路由器设计文档。

  • 路由毒化:如果一个节点A发现节点B变为不可达,那么A就要毒化从A到B的路由(也就是将去往B节点的费用设置为无穷),并且将毒化信息传播给所有邻居。如果A的某个邻居C原本是经过A去往B的,那么C去往B的路由也被毒化,同时C向它的邻居也传播毒化信息,以此类推。这个过程就像是毒性的传播一样。最终,通过A-B链路去往B的那些节点都会被毒化,从而没有路由会再利用这个失效的A-B链路。
  • 横向分割:如果节点A是通过B去往C的,那么A不告诉B:“我能到达C”。从而避免再B-C链路失效以后,B选择通过A来到达C。这个方法只能避免2个节点组成的路由环路。
  • Holddown:在去往C的路由被毒化的一段时间内,不再接受邻居通告的任何去往C节点的路由,因为这个路由可能也使用了失效的链路,只不过尚未被毒化。
  • 毒性逆转:一般与横向分割和Holddown一起使用。如果C接受到A的毒化路由以后也中毒,那么C要把自己毒化后的路由发给A。从而A能更新邻居的DV使其不包含失效的路由。

设计文档

路由器设计

Router类设计图: https://www.processon.com/vie...

我们的路由器实例是运行在同一台机器上的,它们之间通过UDP进行通信。

路由器类的主要成员

  • prot是本路由器的监听的端口。路由器与路由器之间通过UDP socket进行通信(交换路由信息、发送普通消息报文)。由于prot肯定是全局唯一的,因此我们也将它用作路由器的标识符。
  • neighbors存储直连的邻居信息,包括邻居的port、链路的cost。为了加速查询,它的数据结构是一个以邻居port为key的Map。

    • 它是网络拓扑变化的根本来源,它的更新会触发ls算法或dv算法的执行、ls广播或dv通告。
    • 当修改网络拓扑时,修改它,网络拓扑的变化信息就能扩散到整个网络
    • adjacencyList、DVs的更新从根本上来说都来自于它的更新。
    • 详见 https://www.processon.com/dia...
    • 算法为ls时,将它广播到整个网络
    • 算法为dv时,在计算自己的dv(也就是路由表)的时候需要用到它
  • routeTable是路由器的路由表。用来转发数据包。

    • 它是ls或dv的计算结果,不要直接修改routeTable,而是修改数据来源(也就是neighbors或adjacencyList或neighborsDVs),然后触发路由算法,从而更新路由表。
    • 道理类似于:我们不应该直接修改编译器的输出代码,而应该去修改输入编译器的源代码,然后重新编译。从而输出会相应地改变。
  • adjacencyList只在链路算法为ls的时候使用,它是存储了整个网络信息的邻接表。当接收到ls广播,或自己的直连链路变化(也就是neighbors变化),都要触发它的更新。

    • 使用邻接链表运行Dijkstra算法时,要忽略那些单向的链路(也就是说,如果A的邻居中有B,但B的邻居中没有A,那么不算这条链路)。
    • Dijkstra算法的输出只包括从本节点可达的节点,利用这一点,可以定期将adjacencyList中已经不可达的节点的邻居表删除。
  • neighborsDVs(在设计图中的DVs)维护了所有邻居发来的DV通告。为了加速存取,它的数据结构是以邻居port为key的Map。

前后端设计

前端是用Angular5和typescript制作的简单UI,运行在浏览器中;后端是用Node.js写的服务器,模拟路由是完全在后端进行的。前端与后端之间通过WebSocket而不是HTTP来通信,以便后端能主动、实时地发送信息给前端显示。

前端主要包含4个部分:

  1. BackendService负责通过WebSocket与后端进行通信;
  2. NetworkService负责根据后端发来的消息来绘制UI,并响应用户在UI上的操作;
  3. PanelComponent负责展示用户选中的路由器或链路的信息,并提供一些针对选中对象的操作。
  4. Chrome(或其他浏览器)控制台。后端运行的路由器实例产生的日志将通过Websocket连接发送到前端,前端将日志打印在控制台。用户如果想要查看路由器的运行过程需要打开控制台再刷新页面。由于浏览器的控制台自带filter功能,用户可以选择只查看某个路由器发出的日志、某种操作发出的日志。

后端主要包含3个文件:

  1. server.ts负责监听WebSocket端口、调用RouterController来操作路由器和链路;
  2. RouterController.ts负责维护并操作网络中所有的路由器实例,比如连接路由器、关闭路由器、改变路由器之间的链路,它提供操作网络的接口给server.ts;
  3. router.ts定义了路由器类,其实现了ls算法和dv算法,并提供操作单个路由器的接口给RouterController.ts。

配置和运行

先安装node.js。
克隆这个仓库,切换到dev分支

  1. 运行后端程序。命令行进入server文件夹,依次执行“npm install”来安装后端依赖,“npm run build”来编译后端项目(此命令会一直监视文件变化并重新编译)。再打开一个命令行窗口并进入server文件夹,执行“npm run serve”来运行后端项目,看到server is listening on port 8999表示服务端成功运行。

  1. 运行前端程序。然后从命令行进入client文件夹,依次执行“npm install”和“ng serve”。看到已下信息表示客户端网页已经可以可以访问。


打开浏览器,访问“http://localhost:4200/”即可。如果还想要查看路由器日志可以打开浏览器控制台并刷新页面。如果出现“socket发生错误,点击确定刷新页面”弹窗,表示客户端无法通过WebSocket连接到后端,请确保后端正在运行。

默认情况下,运行的是dv算法的路由器。如果要换成ls算法,修改“router.ts”的这一行:

将“dv”改为“ls”(“npm run build”命令行窗口会监测到变化并重新编译)。然后重新执行“npm run serve”来运行后端项目。

运行结果


左上角的操作栏可以添加、删除路由器和链路。点击路由器或链路,会在右边栏显示它的信息和一些操作。路由日志显示在浏览器控制台中,如果想要只查看某个路由器的日志或某个操作的日志,只需要在控制带的Filter输入框中输入过滤字符串,比如“9014log”,或“route table has changed”。

可以通过这个项目来自定义网络拓扑、操作网络拓扑,并观察路由表的变化。具体的例子在视频中展示。

阅读资料

《计算机网络 自顶向下方法 第六版》
https://en.wikipedia.org/wiki...
https://en.wikipedia.org/wiki...
https://en.wikipedia.org/wiki...
https://en.wikipedia.org/wiki...
https://en.wikipedia.org/wiki...
https://en.wikipedia.org/wiki...

[Angular, TypeScript, 路由算法] 模拟IP层路由协议,实现LS算法、洪泛算法、DV算法、路由毒化的更多相关文章

  1. 关闭iOS原生MPVolumeView音频路由菜单

    我正在使用MPVolumeView允许用户在使用我的应用程序时控制他喜欢的音频路径.该代码显示了该视图:当用户点击音频路由按钮时,会出现一个带有可用选项的菜单.问题:显示音量视图的屏幕可能需要隐藏,因为我的应用程序处理各种事件,我想同时隐藏音频路由菜单我的问题:有没有人知道是否可以手动关闭MPVolumeView的音频路由选择菜单而无需用户按下取消按钮?解决方法在iOS8上,您可以使用以下使用私有API的代码

  2. iOS:使用蓝牙音频输出(kAudioSessionProperty_OverrideCategoryEnableBluetoothInput)AudioSession

    >如果有可用的A2DP设备,我的音频路由将始终自动切换到kAudioSessionOutputRoute_BluetoothA2DP路由.如何防止此路线更改?我希望你们中的一些人可以帮助我解决这些问题.这对我对CoreAudio的整体理解,特别是AudioSession框架,真的有帮助.解决方法AudioSession是一项棘手的业务.1.BluetoothHFPaudiooutputisonlypossibleincaseofAudioSessionkAudioSessionCategory_PlayA

  3. 用Swift实现MD5算法&引入第三方类库MBProgressHUD

    之前项目里面是用objc写的MD5加密算法,最近在用swift重写以前的项目,遇到了这个问题。顺带解决掉的还有如何引入第三方的类库,例如MBProgressHUD等一些特别好的控件解决的方法其实是用objc和swift混合编程的方法,利用Bridging-header文件。你可以简单的理解为在一个用swift语言开发的工程中,引入objective-c文件是需要做的一个串联文件,好比架设了一个桥,让swift中也可以调用objective-c的类库和frame等等。

  4. swift排序算法和数据结构

    vararrayNumber:[Int]=[2,4,216)">6,216)">7,216)">3,216)">8,216)">1]//冒泡排序funcmaopao->[Int]{forvari=0;i

  5. swift - 函数指针的应用 - 避免重复算法

    =nil;})}privatefuncsearch(selector:(Employee->Bool))->[Employee]{varresults=[Employee]();foreinemployees{if(selector(e)){results.append(e);}}returnresults;}}

  6. 如何用 Swift 实现 A* 寻路算法

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  7. swift算法实践1

    在通常的表达式中,二元运算符总是置于与之相关的两个运算对象之间,所以,这种表示法也称为中缀表示。波兰逻辑学家J.Lukasiewicz于1929年提出了另一种表示表达式的方法。逆波兰表达式,它的语法规定,表达式必须以逆波兰表达式的方式给出。如果,该字符优先关系高于此运算符栈顶的运算符,则将该运算符入栈。倘若不是的话,则将栈顶的运算符从栈中弹出,直到栈顶运算符的优先级低于当前运算符,将该字符入栈。

  8. swift算法实践2

    字符串hash算法Time33在效率和随机性两方面上俱佳。对于一个Hash函数,评价其优劣的标准应为随机性,即对任意一组标本,进入Hash表每一个单元之概率的平均程度,因为这个概率越平均,数据在表中的分布就越平均,表的空间利用率就越高。Times33的算法很简单,就是不断的乘33,见下面算法原型。

  9. swift算法实践3)-KMP算法字符串匹配

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  10. swift算法实践4)-trie自动机

    1、trie自动机是识别字符串的确定性有向无环自动机2、图示3、构造代码F包括了状态q所对应的P中的字符串

随机推荐

  1. Angular2 innerHtml删除样式

    我正在使用innerHtml并在我的cms中设置html,响应似乎没问题,如果我这样打印:{{poi.content}}它给了我正确的内容:``但是当我使用[innerHtml]=“poi.content”时,它会给我这个html:当我使用[innerHtml]时,有谁知道为什么它会剥离我的样式Angular2清理动态添加的HTML,样式,……

  2. 为Angular根组件/模块指定@Input()参数

    我有3个根组件,由根AppModule引导.你如何为其中一个组件指定@input()参数?也不由AppModalComponent获取:它是未定义的.据我所知,你不能将@input()传递给bootstraped组件.但您可以使用其他方法来做到这一点–将值作为属性传递.index.html:app.component.ts:

  3. angular-ui-bootstrap – 如何为angular ui-bootstrap tabs指令指定href参数

    我正在使用角度ui-bootstrap库,但我不知道如何为每个选项卡指定自定义href.在角度ui-bootstrap文档中,指定了一个可选参数select(),但我不知道如何使用它来自定义每个选项卡的链接另一种重新定义问题的方法是如何使用带有角度ui-bootstrap选项卡的路由我希望现在还不算太晚,但我今天遇到了同样的问题.你可以通过以下方式实现:1)在控制器中定义选项卡href:2)声明一个函数来改变控制器中的散列:3)使用以下标记:我不确定这是否是最好的方法,我很乐意听取别人的意见.

  4. 离子框架 – 标签内部的ng-click不起作用

    >为什么标签标签内的按钮不起作用?>但是标签外的按钮(登陆)工作正常,为什么?>请帮我解决这个问题.我需要在点击时做出回复按钮workingdemo解决方案就是不要为物品使用标签.而只是使用divHTML

  5. Angular 2:将值传递给路由数据解析

    我正在尝试编写一个DataResolver服务,允许Angular2路由器在初始化组件之前预加载数据.解析器需要调用不同的API端点来获取适合于正在加载的路由的数据.我正在构建一个通用解析器,而不是为我的许多组件中的每个组件设置一个解析器.因此,我想在路由定义中传递指向正确端点的自定义输入.例如,考虑以下路线:app.routes.ts在第一个实例中,解析器需要调用/path/to/resourc

  6. angularjs – 解释ngModel管道,解析器,格式化程序,viewChangeListeners和$watchers的顺序

    换句话说:如果在模型更新之前触发了“ng-change”,我可以理解,但是我很难理解在更新模型之后以及在完成填充更改之前触发函数绑定属性.如果您读到这里:祝贺并感谢您的耐心等待!

  7. 角度5模板形式检测形式有效性状态的变化

    为了拥有一个可以监听其包含的表单的有效性状态的变化的组件并执行某些组件的方法,是reactiveforms的方法吗?

  8. Angular 2 CSV文件下载

    我在springboot应用程序中有我的后端,从那里我返回一个.csv文件WheniamhittingtheURLinbrowsercsvfileisgettingdownloaded.现在我试图从我的角度2应用程序中点击此URL,代码是这样的:零件:服务:我正在下载文件,但它像ActuallyitshouldbeBook.csv请指导我缺少的东西.有一种解决方法,但您需要创建一个页面上的元

  9. angularjs – Angular UI-Grid:过滤后如何获取总项数

    提前致谢:)你应该避免使用jQuery并与API进行交互.首先需要在网格创建事件中保存对API的引用.您应该已经知道总行数.您可以使用以下命令获取可见/已过滤行数:要么您可以使用以下命令获取所选行的数量:

  10. angularjs – 迁移gulp进程以包含typescript

    或者我应该使用tsc作为我的主要构建工具,让它解决依赖关系,创建映射文件并制作捆绑包?

返回
顶部