计算机网络GBN和路由算法实验报告要点
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
计算机网络实验报告
----GBN和路由算法
姓名:房皓学号:13410801 教师:尹辉
GBN模拟实验
1.实验目的
运用java编程语言实现基于Go-Back-N的可靠数据传输软件。
2.实验意义
通过本实验,使学生能够对可靠数据传输原理有进一步的理解和掌握。
3.实验背景
Go-Back-N的有限状态机模型表示如下图所示:
(a)
(b)
图为Go-Back-N的有限状态机模型(a)发送端(b)接受端
4.实验步骤
(1)选择java编程语言编程实现基于Go-Back-N的可靠数据传输软件。
(2)在实际网络环境或模拟不可靠网络环境中测试和验证自己的可靠数据传输软件。
5.实验环境
(1)实验语言:JAVA
(2)实验平台:Eclipse
(3)引用库函数:随机(Random)库、计时库(Timer)6.类概览与描述
(1)Sender类:继承于Thread(线程)类,模拟发送方的一切功能,主要功能函数有:
A.Public void run()——启动函数,标识开始发送数
据包
B.Sender()——构造函数,分配并初始化窗口值
C.Public void getack(in tack)——ACK接收函数,接
收接收方返回的ACK并进行验证是否为期待的
ACK值(若不是,则重发)
D.Public void time()——定时器函数,初始化定时,计时并记录超时与否的状态
(2)Receiver类:继承于Thread(线程)类,模拟接收方的一切功能,主要功能函数有:
A.Public void run()——启动函数,标识开始等待并接收数据包
B.Void Receive(int data,Sender s)——数据包接收函数,功能强大!主要包括:接收数据包,验证
数据包,判断与丢弃数据包,发送ack等
(3)Timers类:继承于TimerTask(计时器)类,具有自定义定时与超时提醒的功能,主要功能函数有:
A.Public void run()——启动函数,标识开始计时(这里预设的是2秒的时间),超时后提醒并且停止
计时器
B.Public Timers()——构造函数,清0计时器,等待下一次启动
(4)GBN类:继承于Thread(线程)类,是主函数类,具有本程序的核心功能,这里先作一部分简单介绍,主
要函数功能有:
A.Static void senddelay(int x) throws
InterruptedExceptionPublic Timers()——随机延
迟函数,模拟数据包发送传输过程中的随机延
迟,常用延迟值分别为:300ms, 750ms, 1200ms,
3000ms等
B.Public static void main(String[] args) throws
IOException, InterruptedException()——主函数,
功能强大,主要包含以下几大方面:
①开启发送端与接收端(包括计时器)
②超时或者ACK不匹配等情况导致的发送方
重新发送数据包
③(第一次)发送当前窗口内的数据包
④随机函数模拟数据包发送过程中的丢包
情况
⑤实时更新与显示当前窗口内的数据包情
况
⑥统计每一个数据包被发送过的次数(含重
发)并最终显示出来
C. static void OutputWindow(Sender s) ——输出
当前窗口状态函数。
7.代码展示与描述
(一)Sender类
import java.util.Timer;
public class Sender extends Thread{
public int windowsize=4; //发送方窗口长度设为3
public String[] data={"data1","data2","data3",
"data4","data5","data6","data7"}; //模拟七个数据包
public int sign[]={0,1,2,3,4,5,6}; //为7个数据包标号
public int localack=-1; //保存最近收到的ACK
public Timers litime=null; //定时器(这里定为2秒)
public int switches=0; //超时标志,1为超时
public int windowsign[]; //当前窗口内待发的数据分组的序号
public int acksign[]={1,1,1,1,1,1,1}; //为0表示收到正确ACK,为1表示收
到错误的ACK,必须重发!
public int sent[]={1,1,1,1,1,1,1};//发送标记,1未发送,0已发送
public int acknowledged[]={1,1,1,1,1,1,1};//接收标记,1未接收,0已接收
public Sender(){
windowsign=new int[windowsize]; //给窗口分配指定大小的空间
for(int i=0;i<windowsize;i++)
windowsign[i]=sign[i]; //窗口初始化时存放前3个序号
}
public void run(){
System.out.println("发送方:现在开始发送分组数据!");
}
public void getack(int ack){
System.out.println("发送方:收到了ACK,序号为"+ack+",现在开始确认!
");
if(ack!=localack+1){
System.out.println("发送方:经验证,这不是发送方正期待的ACK,即
将重发序号为"+(localack+1)+"的数据分组!");
//acksign[localack+1]=1;
}
else{
localack=ack; //表示正确确认了ACK
acksign[localack]=0;
}
}
public void time(){
switches=0; //标志初始化为0
litime=new Timers();
Timer limit=new Timer();
limit.schedule(litime, 0,100);
}
}
(二)Receiver类
import java.util.Random;
public class Receiver extends Thread{
public int lastdata=-1;
public int expectdata;
public Sender sender;
public void run(Sender s){
sender=s;
System.out.println("接收方:现在接收分组数据!");
}
void receive(int data, Sender s){
sender=s; //发送方的参数传递System.out.println("接收方:收到了序号为"+data+"的分组!");
if(data==lastdata+1){
//数据包序号校验,若连续则是正确/所期待的
System.out.println("接收方:该数据分组正是所期待的,接受它并准备回送对应的ACK!");
if(sender.litime.limit<20){ //判断是否超时(2秒)
lastdata++; //更新本地保存的数据包序号变量
//ack=lastdata; //获取本场保存的数据包序号
sender.getack(lastdata);
}
else{
expectdata=lastdata+1;
System.out.println("发送方:计时超时!!(未丢包但是时间超过2秒)即将重发序号为"+expectdata+"的数据分组!");
//sender.acksign[lastdata+1]=1;
sender.switches=1; //如果超时,设置超时状态并显示警告
}
//lastdata=data; //更新本地保存的数据包序号变量
//respond(lastdata+1); //回送该正确接收的数据包对应的ACK }
else{
System.out.println("接收方:该数据分组不是接收方所期待的,该分组将被丢弃,接收方准备回送最后接受的数据分组对应的ACK!");
//respond(lastdata);
//若不是所期待的数据包则丢弃并且重发上一次的ACK
if(sender.litime.limit<20){ //判断是否超时(2秒)
sender.getack(lastdata);
}
else{
expectdata=lastdata+1;
System.out.println("发送方:计时超时!!(未丢包但是时间超过2秒)发送方即将重发序号为"+expectdata+"的数据分组!");
sender.switches=1; //如果超时,设置超时状态并显
}
}
}
}
(三)Timers类
import java.util.TimerTask;
public class Timers extends TimerTask {
public int switches;
public int limit;
public void run(){
if(limit<20) limit++; //计时2秒
else {
switches=-1;
this.cancel();
} //开关为-1表示超时,并且停止计时器}
public Timers(){
System.out.println("发送方:现在开始计时");
switches=0; //启动计时器时全部初始化
limit=0;
}
}
(四)GBN类
import .*;
import java.util.Random;
import java.io.*;
public class GBN extends Thread{
static void senddelay(int x,int y) throws InterruptedException{
if(x==1) {sleep(300); System.out.println("发送数据分组"+y+"时发生延迟:300毫秒!"); }
else if(x==2) {sleep(750); System.out.println("发送数据分组"+y+"时发生延迟:750毫秒!");}
else if(x==3) {sleep(1200);System.out.println("发送数据分组"+y+"时发生延迟:1200毫秒!");}
else if(x==4) {sleep(2500);System.out.println("发送数据分组"+y+"时发生延迟:2500毫秒!");}
else if(x==5) {sleep(3000);System.out.println("发送数据分组"+y+"时发生延迟:3000毫秒!");}
}
static void OutputWindow(Sender s){
for(int k=0;k<s.windowsize;k++){
//表示至少成功发送并确认了一个数据分组
s.windowsign[k]++;
//这种情况下滑动窗口向前移动!
}
System.out.println();
System.out.println("当前窗口内的分组情况为:"); //
显示当前窗口内数据包情况
for(int p=0;p<s.windowsize;p++){
if(s.windowsign[p]<=6)
if(s.sent[s.windowsign[p]]==0 ){
System.out.println("第"+p+"号窗口里面存放的是序号为
"+s.windowsign[p]+"的待确认的数据分组!");
}
else
System.out.println("第"+p+"号窗口里面存放的是序号为
"+s.windowsign[p]+"的待发送的数据分组!");
else
System.out.println("第"+p+"号窗口已经空了,并且后续窗口、发送方没有要发送
的数据分组了!");
}
System.out.println();
}
public static void main(String[] args) throws IOException, InterruptedException
{
Sender s=new Sender();
Receiver re=new Receiver();
s.start(); //发送端启动
re.run(s); //接收端启动
sleep(1000); //延迟处理
//int[] retimes=new int[7]; //计算每个分组被发送的次数
//for(int i=0;i<7;i++) retimes[i]=0; //数据包顺次发送
for(int i=0;i<=s.sign.length;){
while(i>s.localack+1){ //尚有未确认的数据包,重发!
System.out.println("发送方:现在发送序号为
"+(s.localack+1)+"的数据分组");
//retimes[s.localack+1]++;
int ran=new Random().nextInt(4);
int randelay=new Random().nextInt(6);
s.time();
senddelay(randelay,s.localack+1); //设置随机值,模拟数据传输延迟
if(ran!=1) {
re.receive(s.localack+1,s);
//设置随机值,模拟数据丢包过程
if(s.localack>=0)
if(s.acksign[s.localack]==0) {
if(s.localack+3<=6) s.sent[s.localack+3]=0;
OutputWindow(s);
}
}
else System.out.println("序号为"+(s.localack+1)+"的分组在传给接收方途中发生了丢包!");
}
if(i!=s.sign.length){
if(i==0){
System.out.println();
System.out.println("发送方:现在发送序号为0~2的数据分组");
s.sent[0]=0;
s.sent[1]=0;
s.sent[2]=0;
System.out.println();
int ran1=new Random().nextInt(4);
int randelay1=new Random().nextInt(6);
s.time(); //计时开始(2秒时间)
senddelay(randelay1,0); //设置随机值,模拟数据传输延迟
if(ran1!=1) {
re.receive(s.sign[0],s);
//设置随机值,模拟数据丢包过程
if(s.acksign[0]==0) {
s.sent[3]=0;
s.acknowledged[0]=0;
OutputWindow(s);
}
}
else System.out.println("序号为"+"0"+"的分组在传给接收方途中发生了丢包!");
i++;
//retimes[0]++;
int ran2=new Random().nextInt(4);
int randelay2=new Random().nextInt(6);
s.time(); //计时开始(2秒时间)
senddelay(randelay2,1); //设置随机值,模拟数据传输延迟
if(ran2!=1) {
re.receive(s.sign[1],s);
//设置随机值,模拟数据丢包过程
if(s.acksign[1]==0) {
s.sent[4]=0;
//retimes[4]++;
s.acknowledged[1]=0;
OutputWindow(s);
}
}
else System.out.println("序号为"+"1"+"的分组在传给接收方途中发生了丢包!");
i++;
//retimes[1]++;
int ran3=new Random().nextInt(4);
int randelay3=new Random().nextInt(6);
s.time(); //计时开始(2秒时间)
senddelay(randelay3,2); //设置随机值,模拟数据传输延迟
if(ran3!=1) {
re.receive(s.sign[2],s);
//设置随机值,模拟数据丢包过程
if(s.acksign[2]==0) {
s.sent[5]=0;
//retimes[5]++;
s.acknowledged[2]=0;
OutputWindow(s);
}
}
else System.out.println("序号为"+"2"+"的分组在传给接收方途中发生了丢包!");
i++;
//retimes[2]++;
}
else{
System.out.println();
if(s.sent[i]==0){
System.out.println("发送方:现在发送序号为"+i+"的数据分组");
}
else
System.out.println("发送方:现在发送序号为"+i+"的数据分组");
int ran=new Random().nextInt(4);
int randelay=new Random().nextInt(6);
s.time(); //计时开始(2秒时间)
senddelay(randelay,i); //设置随机值,模拟数据传输延迟
if(ran!=1) {
re.receive(s.sign[i],s);//设置随机值,模拟数据丢包过程
if(s.acksign[i]==0) {
if(i+3<=6){
s.sent[i+3]=0;
//System.out.println("发送方现在发送序号为
"+(i+3)+"的数据分组");
}
s.acknowledged[i]=0;
OutputWindow(s);
}
}
else System.out.println("序号为"+i+"的分组在传给接收方途中发生了丢包!");
//System.out.println("i=="+i);
//System.out.println("s.localack"+s.localack);
i++;
}
}
else
break;
}
/*System.out.println();System.out.println("以下是每个数据分组被发送过的次数的统计结果");
for(int i=0;i<7;i++) //显示关于每个数据包发送次数的统计表
System.out.println("序号为"+i+"的数据分组被发送过的次数为:
"+retimes[i]);*/
System.out.println("全部数据发送完毕!");
System.exit(0);
}
}
8.程序运行结果部分截图
路由算法实验
1. 实验目的
1. 深入理解分布式路由选择算法,以最简单的DV算法来增
强对路由算法的认识
2.理解、掌握和利用距离向量算法
3.所实现的路由器模拟Internet上的IP路由器。
它能确定网络的最短路由,并在这些利用上传输分组。
2. 实验意义
通过本实验,使学生能够对路由原理和路由算法有进一步的理解和掌握。
3. 实验背景
距离矢量算法,也称为Bellman-Ford shortest path algorithm,每个路由器都定期或拓扑结构突发变化时与其相邻的所有路由器交换路由表,据此更新它们自己的路由表。
DV算法工作方式:每个路由器维护一张路由表,表中分为三个表项:目的地址,列出了当前可达的目的网络地址;到达目的地址下一跳,列出了下一跳的IP地址;到达目的地址的代价,以距离或跳数为表征。
路由表更新规则:
1.发现了一条到达某目的的新路由,而该路由在原来的路由表中不存在(即发现了一条新路由),则在路由表中增
加该路由。
2.发现了一条到达某目的的、距离更短的新路由,则用该路由替换原有的路由。
3.到达某目的的一条路由,其后继结点到达该目的地的距离发生了变化,则需要更新该路由的距离。
4. 实验步骤
选择C编程语言编程实现DV(距离矢量)路由算法5. 实验环境
(1)实验语言:C
(2)实验平台:VC++6.0
(3)引用头文件:stdio.h、stdlib.h、conio.h
6. 函数概览与描述
(1) void InitData(FILE* pfile)
主要功能:从文件中读取路由表的初始信息(2) void OutputRoutData()
主要功能:打印路由表
(3) void Communication(int recv, int send)
主要功能:向邻近节点发送自己的路由表信息(4) void Exchange()
主要功能:根据新路由表信息更新自己的路由表(5) void main()
主要功能:调用以上函数,完成程序
7. 代码展示与描述
(一)数据结构定义
typedef struct
{
int dis; //记录距离
int from; //记录中间节点
}RoutNode;
(二)void InitData(FILE* pfile)函数
void InitData(FILE* pfile)
{
char num[10];
int i = 0;
char c;
int m, n;
fseek(pfile, 0, 0); //定位到文件头
for (m = 0; !feof(pfile) && m < ROUTNUM; m++)
{
for (n = 0; !feof(pfile) && n < ROUTNUM; n++)
{
while (!feof(pfile))
{
c = fgetc(pfile);
if (c == ',')
{
num[i] = '\0'; //添加字符串结束标志
data[m][n].dis = atoi(num); //字符串转换成整型
data[m][n].from = -1; //没有中间节点
i = 0; //准备读取下一个数
break;
}
else if ((c >= '0' && c <= '9') || c == '-')
{
num[i++] = c;
}
}
}
}
}
(三)void OutputRoutData()函数
void OutputRoutData() //打印路由表
{
int i, j;
printf(" ");
for (i = 0; i < ROUTNUM; i++)
{
printf(" %c ", i + 65);
}
printf("\n");
for (i = 0; i < ROUTNUM; i++)
{
printf("%c ", i + 65);
for (j = 0; j < ROUTNUM; j++)
{
if (data[i][j].dis < 0)
printf(" -");
else
if(data[i][j].dis > 10 || data[i][j].dis == 10)
printf(" %d", data[i][j].dis);
else
printf(" %d", data[i][j].dis);
if (data[i][j].from < 0)
printf(" - ");
else
printf(" %c ", data[i][j].from + 65);
}
printf("\n");
}
}
(四)void Communication(int recv, int send)函数
void Communication(int recv, int send) //信息交换,recv信息接收方,send信息发送方
{
int i;
for (i = 0; i < ROUTNUM; i++)
{
if (data[send][i].dis > 0) //发送方到i节点有路径
{
if (data[recv][i].dis < 0) //接收方到i节点没路径
{
data[recv][i].dis = data[send][i].dis + data[recv][send].dis; //更改接收方到i节点的路径信息
data[recv][i].from = send; //记录中间节点
}
else if (data[recv][i].dis > data[send][i].dis + data[recv][send].dis)//接收方到i节点有路径,但较大,一下两步是更新操作
{
data[recv][i].dis = data[send][i].dis + data[recv][send].dis;
data[recv][i].from = send;
}
}
}
}
(五)void Exchange()函数
void Exchange() //更新路由表
{
int i, j;
for (i = 0; i < ROUTNUM; i++)
{
for (j = 0; j < ROUTNUM; j++)
{
if (data[i][j].dis > 0 && data[i][j].from < 0 )
{
Communication(j, i);
}
}
}
}
(六)void main()函数
void main()
{
int start, end, i, j; //start开始节点,end目的节点
FILE *pfile;
pfile = fopen("1.txt", "r");
if (pfile == NULL)//文件不存在,错误
{
printf("文件打开错误,按任意键退出.\n");
getch();
return;
}
else
InitData(pfile);//读取路由表信息
fclose(pfile);
printf("\n路由表初始:\n");
//OutputRoutData();
for (i = 0; i<ROUTNUM; i++) //打印初始的路由表
{
printf("%c||", i + 65);
for (j = 0; j < ROUTNUM; j++)
if (data[i][j].dis > 0 )//|| data[i][j].dis == 0
//if(data[i][j].dis > 9)
// printf("<%c %d> ", j + 65, data[i][j].dis);
//else
printf("<%c %d> ", j + 65, data[i][j].dis);
//else
// printf("<%c -> ", j + 65);
printf("\n");
}//*/
for (i = 0; i < ROUTNUM; i++)
{
Exchange(); //更新路由表信息
}
printf("\n路由表交换:\n");
OutputRoutData(); //打印交换的路由表
while(1){
printf("输入起始路由节点(%d-%d) : ", 0, ROUTNUM - 1);
scanf("%d", &start);
printf("输入终点路由节点(%d-%d) : ", 0, ROUTNUM - 1);
scanf("%d", &end);
if (start == end || start < 0 || start > ROUTNUM-1 || end < 0 || end > ROUTNUM-1) //输入错误
{
printf("\n输入错误,请按任意键退出\n");
getch();
return;
}
else
{
int cur = start; //cur保存开始节点
int total = 0; //记录总的距离
if (data[start][end].dis < 0)
{
printf("没有路由路径发现!\n");
getch();
return;
} /*end of if*/
printf("%c->", cur + 65);
while (data[cur][end].from >= 0) //输出中间节点
{
total += data[cur][data[cur][end].from].dis;
printf("%c->", data[cur][end].from + 65);
cur = data[cur][end].from;
}
total += data[cur][end].dis;
printf("%c\n总的路由距离= %d", end + 65, total);
printf("\n");
GBN和路由算法实验报告
printf("\n");
printf("\n");
//printf("\n");
//getch();
//return;
}
}
}
8. 程序运行结果部分截图。