当前位置:文档之家› 基于DV算法的路由器模拟设计与实现实验报告

基于DV算法的路由器模拟设计与实现实验报告

基于DV算法的路由器设计与实现实验报告学院:姓名:日期:一.实验目的1.深入理解分布式路由选择算法,以最简单的DV算法来增强对路由算法的认识2.理解、掌握和利用距离向量算法3.所实现的路由器模拟Internet上的IP路由器。

它能确定网络的最短路由,并在这些利用上传输分组二.DV算法描述距离矢量算法,也称为Bellman-Ford shortest path algorithm,每个路由器都定期或拓扑结构突发变化时与其相邻的所有路由器交换路由表,据此更新它们自己的路由表。

DV算法工作方式:每个路由器维护一路由表,表中分为三个表项:目的地址,列出了当前可达的目的网络地址;到达目的地址下一跳,列出了下一跳的IP地址;到达目的地址的代价,以距离或跳数为表征。

路由表更新规则:1.发现了一条到达某目的的新路由,而该路由在原来的路由表中不存在(即发现了一条新路由),则在路由表中增加该路由。

2.发现了一条到达某目的的、距离更短的新路由,则用该路由替换原有的路由。

3.到达某目的的一条路由,其后继结点到达该目的地的距离发生了变化,则需要更新该路由的距离。

在此实验当中,为了实现和模拟的方便,刚开始初始化生成一个网络连接图的二维数组(见mainManager/RoutersInit.java,初始化的二维数组是entity/NetMap.java);每个路由器类包括了路由器ID,端口,routerTable对象,还有两个HashMap(一个存储为每一个相邻路由器的计时器,一个存储每一个相邻路由器的上一次交流时间);路由表采用了两个数组来实现,一个数组存储到各个网络的下一跳,一个数组存储到各个网络的跳数,如下结构,以路由器一为例,(路由表的默认数组和两个真是数组的显示信息,其中下一跳是0表示不可达的下一跳,不是0如2004表示下一跳是2004,在距离数组里,如果是16表示不可达,如果是0,表示到本身路由,不是0或16表示可达且跳数为该数值),如下图路由表左边方框中的信息所示:在路由表中,只登记下一跳而不是完整路由,以真实模拟路由器的DV算法处理。

转发分组时,严格按照路由表进行转发。

如上图,路由器的连接信息在上面图片的左部区域,右部区域分为两部分(一个是路由器接到相邻路由器发来的路由表的实时-------我设置的是每1秒更新一次-------信息,一个是发送或者转发数据的显示信息)。

三.实验要求1.输出路由表:在此实验当中为了实现方便,所有拓扑结构中的路由器都给以显示(可达的,不可达的16以及自己的路由编号):要求对这个连接图的二维数组解析,进行DV算法的模拟。

2.发送分组:每个数字代表一个数据分组发送请求;数据分组发送到数字代表的目的地;如果目的结点不是邻居结点,不能直接发送分组,而必须在路由的各个结点上沿路由转发该分组。

收到数据分组的结点必须输出一行,显示该分组的目的,在图1中的右上角显示了每一秒的路由表的更新情况,每一个路由器都有三个转发进程,发送进程和接收进程。

发送进程每一秒都需要发送自己的路由表信息。

每一个路由器都给自己相邻的路由器设置了一个计时器,如果10秒钟没有收到相邻路由器的信息,就将下一跳设置成0,距离设置成16(表示不可达)。

否则重新开始计数。

2.发送数据:数据分组必须有数据,且在如图1中的点击提交按钮之前,必须在文本框中输入正确的数据格式(传送的目的路由和要传送的数据之间必须要有“#”号分割),如:2003#DDDDDDD,表示目的路由是2003,传送的数据是DDDDDDD。

例如:路由器2006要向2001发送数据,则具体转发过程如下:在RouterTablePacket 中有Hops(初始值是16,每过一跳,hops减1,当hops是1的时候,就不再进行转发了,相当于TTL:Time to Live)属性,分组应该在Hops规定的时间或步数到达目的结点,否则丢弃之。

分组经过每个中间结点时,将其TTL减1。

若TTL=1,丢弃,否则继续转发。

3.关于时间定时:每个路由器每1秒钟发出它们的路由表;每个路由器根据收到的路由表更新它们自己的路由表;路由器必须具备检测邻居是否活动的能力,如果路由器在10秒钟没有收到邻居发来的更新,则认为邻居不可达。

4.显示活动的相邻路由:用一个特定的表格来显示与当前路由相邻的路由器的信息。

5.关于拓扑结构:路由器必须具备路由器故障和恢复的能力;这里假设链路不会出现故障,分组不会丢失和出错;如果路由器在给定时间未运行,表示路由器故障,如果重启运行,则认为路由器故障恢复;当然,假设通信是双向的。

四.实验用例编程语言:java;开发环境:jdk1.6.0_02、Myeclipse8.6,测试用例为二维数组的维数个(你可以随便写出一个对称的二维数组,程序可以自己解析的,我用的都是活代码),如下如所示我写的一个拓扑图的二维数组,如图:此实验是模仿DV算法,应用java中的多线程来模拟多个路由器,并且实现路由器之间的路由表和数据的传送。

实验中路由表的数据结构相比真实的DV算法发生了变化,所以程序在实现过程当中尽量的按照实验所用的路由表结构来完成功能,但是这不影响其主要思想的实现。

1.拓扑结构:为了模拟路由表的更新,首先是先确立六个结点网络的拓扑结构,由于是应用多线程来模拟各个路由器,所以在实验过程当中可以随时挂起某个或多个路由器来模拟网络拓扑的变化,之后仍然可以恢复挂起的路由器。

网络的初始拓扑结构如图2所示:在程序的mainManager/RoutersInit.java 类中初始化了留个路由器,这六个路由器的每一个实现都是在mainManager/RouterThread.java类中,。

以上图2的初始化二维数组中所规划的网络拓扑结构为标准,根据当前所创建的路由器编号静态初始化每个路由器自己的路由表。

3.数据格式:各个路由器实例之间通过UDP来交换路由表,路由器之间还需要进行数据的传输。

在此,需要定义所传输的路由表和数据的结构,我是全部打成了数据包或者路由表包,具体结构见transportPacket/RouterTablePacket.java(有sourceRouterId和routerTable两个属性),transportPacket/SendDataPacket.java(有sourceRouterId,destRouterId,byte[]data,hops=16四个属性),transportPacket/TotalPacket.java(有type,routerTablePacket,sendDataPacket 三个属性,TotalPacket类定义了具体具体是传输的包是什么类型的)三个类,如果是传输路由表就用RouterTablePacket把路由表包装后再用TotalPacket的sendRouterTable类型来包装,最后用UDP发送出去,如果是传输数据就用SendDataPacket把要传送的数据包装后再用TotalPacket的sendData类型来包装,最后用UDP发送出去,在目的路由器端对收到的数据进行解封装。

五.程序描述为完成所要求功能,程序首先实现了二维数组维数个路由器线程,每一个路由器线程下面又实现了发送线程、接收线程和转发数据线程三个子线程;接收线程下面实现了定时器子线程。

建立一个工程,命名为day12-02_DV_new_hasTimer (名字可以随便起,我是以前的习惯都加上了日期),在此工程下建立源程序文件,每个线程放在单独的java源程序文件当中。

该实验还可以对其中一个路由器进行挂起,别的路由器在10秒后如果收不到这个路由器发来的路由表信息,就将其路由表中的与其对应的相应路由表的值进行修改成不可达,逐渐通知到整个网络。

在这里有点不同于DV算法的是:DV 算法是每个路由器为收到的路由表的每一个简历一个计时器,而该路由器简化了这个设计,是仅仅为相邻的路由器保留一个计时器,这样不仅可以大大减少整个网络的通信量,将计时器的信息保留在存而不是在路由表中,而且采用了hashMap保存后在验证是否联通时,从hashMap中取数据方便快捷。

六、实验结论在实验过程遇到了许多问题,一方面是编程语言的使用,另一方面是对路由算法的理解程度。

三是计时器的用法,尤其是计时器的用法想了将近2个小时,最后通过不懈的调试与算法完善,程序基本实现所要求的功能,有能力模拟DV 算法。

DV算法的优缺点:DV算法简单,容易实现,对于好消息传播的速度快,但是对于坏消息则传播速度慢。

package entity;/*** 常量类* author 郭金磊*since 20131220*/public class Constant {/*** return 返回路由Id的初试值*/public static int getRouterIdBasic(){ return 2001;}/*** return 返回路由端口的初试值*/public static int getPortBasic(){ return 5001;}}package entity;/*** 初始化的网络拓扑图* author 郭金磊*since 20131220*/public class NetMap {/*** return 返回初始化的网络图*/public int[][] getInitInternetMap(){int[][] initVecter=new int[][]{{0,1,16,16,1,16},{1,0,1,16,16,16},{16,1,0,1,1,16},{16,16,1,0,16,1},{1,16,1,16,0,16},{16,16,16,1,16,0}};return initVecter;}}package entity;import java.util.HashMap;/*** 路由器实体类,包含routerId,port,RouterTable,createTimerMapsForNeighbers,lastTimeMaps* author 郭金磊*since 20131220*/public class Router {/*** 产生全局唯一的序列化的实体ID*/private static final long serialVersionUID = -04L;/*** 路由ID*/private int routerId;/*** 路由端口*/private int port;/*** 路由表*/private RouterTable RouterTable;/*** 存储计时器的Map*/private HashMap<Integer,TimeCounter> createTimerMapsForNeighbers=new HashMap<Integer,TimeCounter>();/*** 存储上一次该路由器收到某个路由器的路由表时间*/private HashMap<Integer,Long> lastTimeMaps=new HashMap<Integer,Long>();/*** 默认的构造方法*/public Router() {super();}/*** 有参数routerId和port的构造方法*/public Router(int routerId, int port) {super();this.routerId = routerId;this.port = port;}/*** 有参数routerId和port和routerTable的构造方法*/public Router(int routerId, int port, RouterTable routerTable) { super();this.routerId = routerId;this.port = port;RouterTable = routerTable;}/*** getters 和setters方法* return 相应的属性值*/public int getRouterId() {return routerId;}/*** getters 和setters方法*/public void setRouterId(int routerId) { this.routerId = routerId;}/*** getters 和setters方法* return 相应的属性值*/public int getPort() {return port;}/*** getters 和setters方法*/public void setPort(int port) {this.port = port;}/*** getters 和setters方法* return 相应的属性值*/public RouterTable getRouterTable() {return RouterTable;}/*** getters 和setters方法* return 相应的属性值*/public void setRouterTable(RouterTable routerTable) {RouterTable = routerTable;}/*** getters 和setters方法* return 相应的属性值*/public HashMap<Integer, TimeCounter> getCreateTimerMapsForNeighbers() {return createTimerMapsForNeighbers;}/*** getters 和setters方法* return 相应的属性值*/public void setCreateTimerMapsForNeighbers(HashMap<Integer, TimeCounter> createTimerMapsForNeighbers) { this.createTimerMapsForNeighbers = createTimerMapsForNeighbers;}/*** getters 和setters方法* return 相应的属性值*/public HashMap<Integer, Long> getLastTimeMaps() {return lastTimeMaps;}/*** getters 和setters方法* return 相应的属性值*/public void setLastTimeMaps(HashMap<Integer, Long> lastTimeMaps) { stTimeMaps = lastTimeMaps;}/*** tostring方法*/Overridepublic String toString() {return "Router [routerId=" + routerId + ", port=" + port+ ", RouterTable=" + RouterTable + "]";}}package entity;import java.io.Serializable;import java.util.Arrays;/*** 路由表实体类* author 郭金磊*since 20131220*/public class RouterTable implements Serializable{/*** 产生全局唯一的序列化的实体ID*/private static final long serialVersionUID = 31L;/*** 为每一个路由器设置一个下一跳的数组*/private int [] nextHop;/*** 为每一个路由器设置一个距离的数组*/private int [] distance;/*** 有参数routerId和port的构造方法*/public int[] getDistance() {return distance;}/*** getters 和setters方法* return 相应的属性值*/public void setDistance(int[] distance) { this.distance = distance;}/*** getters 和setters方法* return 相应的属性值*/public int[] getNextHop() {return nextHop;}/*** getters 和setters方法* return 相应的属性值*/public void setNextHop(int[] nextHop) { this.nextHop = nextHop;}/*** tostring方法*/Overridepublic String toString() {return "RouterTable [distance=" + Arrays.toString(distance) + ", nextHop=" + Arrays.toString(nextHop) + "]";}}package entity;import java.util.Timer;import java.util.TimerTask;/*** 计时器类,用于判断是否路由器的联通* author 郭金磊*since 20131220*/public class TimeCounter {/*** 得到邻居的路由器ID*/private int sourceRouterId;/*** 得到本身路由器*/private Router router;/*** 每个这个类一个计时器*/private Timer timer=new Timer();/*** getters 和setters方法* return 相应的属性值*/public int getSourceRouterId() {return sourceRouterId;}/*** getters 和setters方法* return 相应的属性值*/public void setSourceRouterId(int sourceRouterId) { this.sourceRouterId = sourceRouterId;}/*** getters 和setters方法* return 相应的属性值*/public Router getRouter() {return router;}/*** getters 和setters方法* return 相应的属性值*/public void setRouter(Router router) {this.router = router;}/*** 默认的构造方法*/public TimeCounter() {super();}/*** 带参数的构造方法* param sourceRouterId 邻居的路由器ID* param router 得到本身路由器,可以得到本身路由器的很多信息*/public TimeCounter(int sourceRouterId, Router router) {super();this.sourceRouterId = sourceRouterId;this.router = router;}/*** 开启计时器*/public void start() {final long lastTime=router.getLastTimeMaps().get(sourceRouterId);timer.schedule(new TimerTask() {Overridepublic void run() {if(lastTime==router.getLastTimeMaps().get(sourceRouterId)){for(int i=0;i<new NetMap().getInitInternetMap().length;i++){if(router.getRouterTable().getNextHop()[i]==sourceRouterId){router.getRouterTable().getDistance()[i]=16;router.getRouterTable().getNextHop()[i]=0;}}}else{timer.cancel();}}}, 10 * 1000);}/*** 关闭该计时器*/public void close() {timer.cancel();}}package main;import java.awt.BorderLayout;import java.awt.Color;import javax.swing.JFrame;import javax.swing.JTextArea;import mainManager.RouterThread;import mainManager.RoutersInit;import Map;import entity.Router;/*** 主进入界面,进入程序的主控制接口* author 郭金磊*since 20131220*/public class RoutersStart extends JFrame{/*** 产生全局唯一的序列化的实体ID*/private static final long serialVersionUID = -52L;/*** 建立一个全局的JTextArea,用来关闭时窗口是,关闭整个进程而不是线程*/private JTextArea router_MainArea;/*** 初始化多少个路由器*/public RoutersStart(){super("router_MainProcess");router_MainArea=new JTextArea();getContentPane().add(router_MainArea,BorderLayout.CENTER);router_MainArea.append("\n\n\n开始模拟"+new NetMap().getInitInternetMap().length+"个路由器的距离向量路由算法...");setBounds(150,150,500,400);router_MainArea.setBackground(Color.lightGray);setBackground(Color.DARK_GRAY);setVisible(true);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);int length=new NetMap().getInitInternetMap().length;Router[] routers=new RoutersInit().getInitRouters();for(int i=0;i<length;i++){new Thread(new RouterThread(routers[i])).start();}}/*** 主程序的入口* param args 默认的参数,此处不用参数*/public static void main(String[] args) {new RoutersStart();}}package mainManager;import entity.Constant;import Map;import entity.Router;import entity.RouterTable;/*** 读取拓扑图的二维数组数据,来初始化二维数组维数个路由器线程* author 郭金磊*since 20131220*/public class RoutersInit {/*** 初始化路由器数组* return 得到初始化的几个路由器*/public Router[] getInitRouters() {int[][] initNetMap=new NetMap().getInitInternetMap();Router[] routers=new Router[initNetMap.length];RouterTable [] routerTables=new RouterTable[initNetMap.length];for(int i=0;i<initNetMap.length;i++){routers[i]=newRouter(Constant.getRouterIdBasic()+i,Constant.getPortBasic()+i);routerTables[i]=new RouterTable();routerTables[i].setDistance(initNetMap[i]);int [] nextHop=new int[initNetMap.length];for(int j=0;j<initNetMap.length;j++){if(initNetMap[i][j]==1){nextHop[j]=Constant.getRouterIdBasic()+j;}else{nextHop[j]=0;}}routerTables[i].setNextHop(nextHop);routers[i].setRouterTable(routerTables[i]);System.out.println(routers[i]);}return routers;}}package mainManager;import java.awt.BorderLayout;import java.awt.Color;import java.awt.GridLayout;import java.awt.HeadlessException;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.awt.event.WindowAdapter;import java.awt.event.WindowEvent;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.ObjectOutputStream;import .DatagramPacket;import .DatagramSocket;import .InetAddress;import .SocketException;import .UnknownHostException;import java.util.Arrays;import javax.swing.JButton;import javax.swing.JCheckBox;import javax.swing.JFrame;import javax.swing.JLabel;import javax.swing.JPanel;import javax.swing.JScrollPane;import javax.swing.JTextArea;import javax.swing.JTextField;import totalThreads.ForwardThread;import totalThreads.ReceiveThread;import totalThreads.SendThread;import transportPacket.SendDataPacket;import transportPacket.TotalPacket;import entity.Constant;import Map;import entity.Router;import entity.RouterTable;/*** 每一个路由器都有的路由器线程* author 郭金磊*since 20131220*/public class RouterThread extends JFrame implements Runnable { /*** 产生全局唯一的序列化的实体ID*/private static final long serialVersionUID = -05L;/*** 每一个路由器线程一个路由器实体*/private Router router;/*** 每一个路由器实体一个接受路由表线程*/private DatagramSocket receiveSocket =null;/*** 每一个路由器实体一个接受转发的数据线程private DatagramSocket receiveDataSocket =null;/*** 每个路由器线程一个接受线程*/private ReceiveThread receiveThread=null;/*** 每个路由器线程一个发送线程*/private SendThread sendThread=null;/*** 每个路由器线程一个转发线程*/private ForwardThread forwardThread=null;/*** 每个路由器线程一个主窗口*/private JFrame routerFrame;/*** 有三个显示路由器信息的JTextArea,一个路由表,一个路由表的更新信息,一个是发送数据的显示信息*/private JTextArea routerAreaLeft,routerAreaRightNorth,routerAreaRightSouth; // 构造路由器窗口的组件。

相关主题