计算机网络课程的实验
1.距离向量算法
距离向量路由算法要求,每个结点都参与定期交换整个路由表,即把路由表传递给自己与之相连的结点。
首先,当前路由表的组成如下,<目的网络 N,跳数,下一跳地址>
1.1.执行步骤
- 从相邻的 X 路由器接收发送过来的 RIP(Routing Information Protocol) 报文
- 将该 RIP 报文中的下一跳地址修改为 X,且跳数增加 1
- 对每个项目执行如下步骤
a.若原路由表没有 RIP 中的目的网络 N,直接添加到原路由表中
b.若原路由表中有 RIP 中的目的网络 N,但下一跳地址不是 X ,选择跳数少的替换。如果两者跳数一样,则保留原路由表的项。
c.若原路由表中有 RIP 中的目的网络 N,且下一跳地址是 X,使用收到的项替换 - 若超过 180s (RIP 默认 180s)还没有收到相邻路由器的更新路由表,则相邻路由器置为不可达,跳数为 16
算法的缺点:可以看到,距离向量协议传送的是整个路由表,那么报文的大小就和通信子网的结点个数成正比,如果通信子网越大,那么报文也将非常大。
PS:实际运用中,RIP算法只关心跳数,并不关心带宽,反而有可能避开了最有的路线。
2.实验讲义
2.1.讲义截图
2.2.实验要求
3.代码实现
3.1.路由类(用来表示单条路由)
public class Rip {
private String netto;//目的网络
private int number;//目的 网络号 数字类型
private Integer distance;//距离
private String next;//下一跳
public int getNumber(){//用来排序
String number = this.netto;//拷贝一个副本
int ret;
return ret = Integer.parseInt(number.replaceAll("N",""));
}
@Override
public String toString() {
return netto + " " +
+ distance +" "+
next
;
}
public String getNetto() {
return netto;
}
Rip (String netto,int distance,String next){
this.netto = netto;
this.distance = distance;
this.next = next;
}
Rip (String netto,int distance){
this.netto = netto;
this.distance = distance;
}
public void setNetto(String netto) {this.netto = netto;}
public Integer getDistance() {return distance; }
public void setDistance(Integer distance) { this.distance = distance;}
public String getNext() {return next;}
public void setNext(String next) {this.next = next;}
}
3.2.路由表类(用来表示单个路由表)
public class RipTable {
private String TableName;//使用private方法,其它类只能通过get set方法调用
private List<Rip> rips =new ArrayList<Rip>();//存储路由表
public void print() {
System.out.println(TableName+"的路由表");
System.out.println("目的网络"+"\t"+"距离"+"\t"+"下一跳");
for(Rip rip:rips){
System.out.println(rip.toString());
}
}
public void clear(){
rips.clear();
}
RipTable(String tableName){//用于设置路由器名
this.TableName = tableName;
}
public List<Rip> getRips() {
return rips;
}
public String getTableName() {
return TableName;
}
}
3.3.路由表一次更新方法
public class UpdateTable_qs1 {
public static void updateTable(RipTable r1, RipTable r2) {//根据r2更新路由表r1
HashSet<String> set = new HashSet<String>();
for (Rip rip : r1.getRips()) {
set.add(rip.getNetto());//将目的网络加入set表 下面用contain方法判断是否包含
}
for (Rip rip : r2.getRips()) {
rip.setDistance(rip.getDistance() + 1);//将距离+1
rip.setNext(r2.getTableName());//将r2的下一跳全改为r2的表名
}
for (Rip j : r2.getRips()) {//遍历r2路由表
if (!set.contains(j.getNetto()))//set中不包含的情况
{
r1.getRips().add(j);//1、若原路由表没有 RIP 中的目的网络,直接添加到原路由表中
} else {//2、若原路由表中有 RIP 中的目的网络 N
for (Rip i : r1.getRips()) {
if (i.getNetto().equals(j.getNetto())) {//取到相同的目的网络的位置
if (!i.getNext().equals(j.getNext())) {// 但下一跳地址不是 X ,选择跳数少的替换。如果两者跳数一样,则保留原路由表的项
if (j.getDistance() < i.getDistance()) {//只有当r2的跳数小于r1时才替换
i.setDistance(j.getDistance());//替换跳数
i.setNext(j.getNext());//替换下一跳
}
} else {
i.setDistance(j.getDistance());//替换跳数
i.setNext(j.getNext());//替换下一跳
}
}
}
}
}
Collections.sort(r1.getRips(), new Comparator<Rip>() {//定制排序
@Override
public int compare(Rip o1, Rip o2) {
// TODO Auto-generated method stub
return o1.getNumber()-o2.getNumber();
}
});
System.out.println("更新后的"+r1.getTableName()+"路由表为:");
r1.print();
System.out.println("----------------分割线-------------------");
}
}
3.4.递归更新到任一目的网络不可达
说明:这里偷懒了,逻辑是r1,r2路由器互相更新,(是所有的目的网络都不可达,同时更新的情况)每一轮次距离增加2,直到任一里面有一个目的网络跳数到达16则输出并返回。
关于要求稳定状态:如果是两个路由表互相更新,当所有网络都不可达(跳数为16)时,也可以视为稳定状态。
public class goodfastbadlast_qs2 {
public static void updateTable2(RipTable r1, RipTable r2) {//根据r2更新路由表r1
for(Rip r:r1.getRips()){
if(r.getDistance()>=16) {
System.out.println("此时路由表"+r1.getTableName()+"的目的网络"+r.getNetto()+"距离为"+r.getDistance()+"为不可达");
r1.print();
return;
}
}
for(Rip r:r2.getRips()){
if(r.getDistance()>=16){
System.out.println("此时路由表"+r2.getTableName()+"的目的网络"+r.getNetto()+"距离为"+r.getDistance()+"为不可达");
r2.print();
return;
}
}
HashSet<String> set = new HashSet<String>();
for (Rip rip : r1.getRips()) {
set.add(rip.getNetto());//将目的网络加入set表 下面用contain方法判断是否包含
}
for (Rip rip : r2.getRips()) {
rip.setDistance(rip.getDistance() + 1);//将距离+1
rip.setNext(r2.getTableName());//将r2的下一跳全改为r2的表名
}
for (Rip j : r2.getRips()) {//遍历r2路由表
if (!set.contains(j.getNetto()))//set中不包含的情况
{
r1.getRips().add(j);//1、若原路由表没有 RIP 中的目的网络,直接添加到原路由表中
} else {//2、若原路由表中有 RIP 中的目的网络 N
for (Rip i : r1.getRips()) {
if (i.getNetto().equals(j.getNetto())) {//取到相同的目的网络的位置
if (!i.getNext().equals(j.getNext())) {// 但下一跳地址不是 X ,选择跳数少的替换。如果两者跳数一样,则保留原路由表的项
if (j.getDistance() < i.getDistance()) {//只有当r2的跳数小于r1时才替换
i.setDistance(j.getDistance());//替换跳数
i.setNext(j.getNext());//替换下一跳
}
} else {
i.setDistance(j.getDistance());//替换跳数
i.setNext(j.getNext());//替换下一跳
}
}
}
}
}
Collections.sort(r1.getRips(), new Comparator<Rip>() {//定制排序
@Override
public int compare(Rip o1, Rip o2) {
// TODO Auto-generated method stub
return o1.getNumber()-o2.getNumber();
}
});
updateTable2(r2,r1);
}
}
3.5.测试类
public class test extends UpdateTable_qs1 {
public static void main(String[] args) {
RipTable ripTable = new RipTable("B");
RipTable ripTable1 = new RipTable("C");
Scanner sc = new Scanner(System.in);
int times = 2, a;
while (times > 0) {
ripTable.clear();
ripTable1.clear();
//第一组数据
// Rip rip=new Rip("N1",7,"A"); ripTable.getRips().add(rip);
// Rip rip1=new Rip("N2",2,"C");ripTable.getRips().add(rip1);
// Rip rip2=new Rip("N6",8,"F");ripTable.getRips().add(rip2);
// Rip rip3=new Rip("N8",4,"E");ripTable.getRips().add(rip3);
// Rip rip4=new Rip("N9",4,"D");ripTable.getRips().add(rip4);
// Rip rip5=new Rip("N2",15); ripTable1.getRips().add(rip5);
// Rip rip6=new Rip("N3",2);ripTable1.getRips().add(rip6);
// Rip rip7=new Rip("N4",8);ripTable1.getRips().add(rip7);
// Rip rip8=new Rip("N8",2);ripTable1.getRips().add(rip8);
// Rip rip9=new Rip("N7",4);ripTable1.getRips().add(rip9);
//第二组数据
Rip rip = new Rip("N1", 5, "A");ripTable.getRips().add(rip);
Rip rip1 = new Rip("N2", 3, "C");ripTable.getRips().add(rip1);
Rip rip2 = new Rip("N6", 6, "F");ripTable.getRips().add(rip2);
Rip rip3 = new Rip("N8", 4, "E");ripTable.getRips().add(rip3);
Rip rip5 = new Rip("N1", 5);ripTable1.getRips().add(rip5);
Rip rip6 = new Rip("N2", 4);ripTable1.getRips().add(rip6);
Rip rip7 = new Rip("N3", 8);ripTable1.getRips().add(rip7);
Rip rip8 = new Rip("N6", 4);ripTable1.getRips().add(rip8);
Rip rip9 = new Rip("N8", 3);ripTable1.getRips().add(rip9);
ripTable.print();
ripTable1.print();
System.out.println("请输入要模拟的功能");
System.out.println("1.更新一次路由表");
System.out.println("2.好消息传的快,坏消息传得慢");
System.out.println("3.按照时间更新路由表");//这个没有写! 逻辑和2差不多
a = sc.nextInt();
switch (a) {
case 1:
updateTable(ripTable, ripTable1);
times--;
break;
case 2:
updateTable2(ripTable,ripTable1);
times--;
break;
}
}
}
}
3.5.运行截图
总结: 关于要求三,把要求二的代码稍微改改,把逻辑改成当跳数为16时,设置为不可达,当所有都为不可达时,也可以视为稳定状态hhh。
实验也查完了, 上面的代码rip算法的逻辑应该是没有问题的,注解也有。如果要拷贝的话,可以根据自己的需求修改一下。