Github: https://github.com/Joilence/n...前端
鏈路狀態協議(Link-state routing protocol)和距離向量路由協議(Distance-vector routing protocol)是分組交換(Packet switching)網絡中最主要的兩種路由協議。本項目的模擬路由器實現了LS路由算法、LS廣播洪泛、DV路由算法,以及防止DV路由環路和無窮計數問題的策略。此外還實現了完整的先後端以便研究者經過UI界面自定義網絡拓撲、控制路由器、查看路由器信息和日誌。node
LS算法要求網絡中每一個節點都收集完整的網絡信息,以鄰接表的形式存儲整個網絡的拓撲結構和全部鏈路的費用,而後根據這個圖來運行路由選擇算法(在這裏咱們選擇Dijkstra算法),計算出從本節點到網絡中全部其餘節點的最低費用路徑。git
爲了讓每一個節點都知道整個網絡的拓撲結構和全部鏈路費用,每一個節點都要將本身直連的鏈路信息廣播給網絡中的全部節點(LS廣播)。要廣播的信息包括本身的鄰居有哪些、到達它們的鏈路開銷分別是多少。github
爲了更新它自己存儲的網絡拓撲圖,在接收到其餘節點的LS廣播時,要根據廣播中的鏈路信息更新本身的鄰接表。算法
同時,在接收到其餘節點的LS廣播時,要將它轉發給本身的全部鄰居,從而這個LS廣播能散播到整個網絡。爲了不廣播風暴(廣播包在網絡中無休止地傳播,致使網絡癱瘓),每一個路由器要辨別接收到的LS廣播包是否是已經接收過。這能夠經過一個廣播包中的序列號字段來作到。每臺ls路由器,每次廣播使用一個遞增的序列號,若是屢次收到來自同一臺路由器且序號相同的廣播,則不更新鄰接表,也不轉發給鄰居,防止廣播風暴。typescript
Dijkstra算法可以計算出圖中全部節點到某個節點的最短路徑。對於一個圖和一個給定的原點,Dijkstra算法不斷選擇一個距離源點最近且還沒有擴展的節點w來擴展,並更新w的鄰居節點到原點的距離。最終,全部被擴展的節點就是從原點能夠到達的節點,它們被擴展時到原點的距離就是最終的最短距離。npm
Dijkstra算法的輸入就是節點維護的鄰接表,所以只要鄰接表有更新,就要觸發Dijkstra算法計算出新的路由表。
那麼鄰接表何時會更新呢?有2種狀況:後端
DV算法不須要全局網絡信息。每一個節點只從直連鄰居接收路由通告,執行DV計算,而後將計算結果分發給直連鄰居。重複這個過程,直到每一個節點的DV計算結果都與上一次的DV計算結果相同,此時網絡中再也不有路由通告,算法終止。瀏覽器
DV算法的思想相對比較簡單:鄰居能到達的節點,我通過這個鄰居也能到達,而且我去目標節點的費用 = 我到鄰居的費用 + 鄰居到目標節點的費用。一個節點的DV存儲的就是這個節點能到達哪些節點、費用分別是多少。服務器
DV算法的輸入是全部鄰居的DV和本身的直連鏈路信息,輸出是本身的DV(也就是路由表)。若是輸出的DV與上次輸出的不一樣,也就是本身的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的策略。詳見路由器設計文檔。
Router類設計圖: https://www.processon.com/vie...
咱們的路由器實例是運行在同一臺機器上的,它們之間經過UDP進行通訊。
neighbors存儲直連的鄰居信息,包括鄰居的port、鏈路的cost。爲了加速查詢,它的數據結構是一個以鄰居port爲key的Map。
routeTable是路由器的路由表。用來轉發數據包。
adjacencyList只在鏈路算法爲ls的時候使用,它是存儲了整個網絡信息的鄰接表。當接收到ls廣播,或本身的直連鏈路變化(也就是neighbors變化),都要觸發它的更新。
前端是用Angular5和typescript製做的簡單UI,運行在瀏覽器中;後端是用Node.js寫的服務器,模擬路由是徹底在後端進行的。前端與後端之間經過WebSocket而不是HTTP來通訊,以便後端能主動、實時地發送信息給前端顯示。
前端主要包含4個部分:
後端主要包含3個文件:
打開瀏覽器,訪問「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...