网络原理实验报告GBN.docx
《网络原理实验报告GBN.docx》由会员分享,可在线阅读,更多相关《网络原理实验报告GBN.docx(13页珍藏版)》请在冰点文库上搜索。
网络原理实验报告GBN
网络原理实验报告
——编程模拟GBN
姓名:
班级:
学号:
教师:
1.实验目的
运用各种编程语言实现基于Go-Back-N的可靠数据传输软件。
PS:
这里使用的是JAVA语言
2.实验意义
通过本实验,使学生能够对可靠数据传输原理有进一步的理解和掌握。
3.实验背景
Go-Back-N的有限状态机模型表示如下图所示:
(a)
(b)
图为Go-Back-N的有限状态机模型(a)发送端(b)接受端
4.实验步骤
(1)选择合适的编程语言编程实现基于Go-Back-N的可靠数据传输软件。
(2)在实际网络环境或模拟不可靠网络环境中测试和验证自己的可靠数据传输软件。
5.实验环境
(1)实验语言:
JAVA
(2)实验平台:
Eclipse
(3)引用库函数:
.net库、随机(Random)库、计时库(Timer)
6.类概览与描述
(1)Sender类:
继承于Thread(线程)类,模拟发送方的一切功能,主要功能函数有:
A.Publicvoidrun()——启动函数,标识开始发送数据包
B.Sender()——构造函数,分配并初始化窗口值
C.Publicvoidgetack(intack)——ACK接收函数,接收接收方返回的ACK并进行验证是否为期待的ACK值(若不是,则重发)
D.Publicvoidtime()——定时器函数,初始化定时,计时并记录超时与否的状态
(2)Receiver类:
继承于Thread(线程)类,模拟接收方的一切功能,主要功能函数有:
A.Publicvoidrun()——启动函数,标识开始等待并接收数据包
B.VoidReceive(intdata,Senders)——数据包接收函数,功能强大!
主要包括:
接收数据包,验证数据包,判断与丢弃数据包等
C.Publicvoidrespond(intack)——ACK发送函数,发送当前接收到的最后一次正确的数据包对应的ACK
(3)Timers类:
继承于TimerTask(计时器)类,具有自定义定时与超时提醒的功能,主要功能函数有:
A.Publicvoidrun()——启动函数,标识开始计时(这里预设的是2秒的时间),超时后提醒并且停止计时器
B.PublicTimers()——构造函数,清0计时器,等待下一次启动
(4)GBN类:
继承于Thread(线程)类,是主函数类,具有本程序的核心功能,这里先作一部分简单介绍,主要函数功能有:
A.Staticvoidsenddelay(intx)throwsInterruptedExceptionPublicTimers()——随机延迟函数,模拟数据包发送传输过程中的随机延迟,常用延迟值分别为:
300ms,750ms,1200ms,3000ms等
B.Publicstaticvoidmain(String[]args)throwsIOException,InterruptedException()——主函数,功能强大,主要包含以下几大方面:
1开启发送端与接收端(包括计时器)
2超时或者ACK不匹配等情况导致的发送方重新发送数据包
3(第一次)发送当前窗口内的数据包
4随机函数模拟数据包发送过程中的丢包情况
5实时更新与显示当前窗口内的数据包情况
6统计每一个数据包被发送过的次数(含重发)并最终显示出来
7.代码展示与描述
(一)Sender类
importjava.util.Timer;
publicclassSenderextendsThread{
publicintwindowsize=3;//发送方窗口长度设为3
publicString[]data={"data1","data2","data3",
"data4","data5","data6","data7"};//模拟七个数据包
publicintsign[]={0,1,2,3,4,5,6};//为7个数据包标号
publicintlocalack=-1;//保存最近收到的ACK
publicTimerslitime=null;//定时器(这里定为2秒)
publicintswitches=0;//超时标志,1为超时
publicintwindowsign[];//当前窗口内待发的数据分组的序号
publicintacksign=0;
//为0表示收到正确ACK,为1表示收到错误的ACK,必须重发!
publicSender(){
windowsign=newint[windowsize];//给窗口分配指定大小的空间
for(inti=0;i<3;i++)
windowsign[i]=sign[i];//窗口初始化时存放前3个序号
}
publicvoidrun(){
System.out.println("发送方开始发送分组数据!
");
}
publicvoidgetack(intack){
System.out.println("发送方收到了ACK,序号为"+ack+"并且开始加以确认!
");
if(ack!
=localack+1){
System.out.println("经验证,这不是发送方正期待的ACK,立刻重发序号为"+(localack+1)+"的数据分组!
");
acksign=1;
}
else{
localack=ack;//表示正确确认了ACK
acksign=0;
}
}
publicvoidtime(){
switches=0;//标志初始化为0
litime=newTimers();
Timerlimit=newTimer();
limit.schedule(litime,0,100);
}
}
(二)Receiver类
importjava.util.Random;
publicclassReceiverextendsThread{
publicintlastdata;
publicSendersender;
publicvoidrun(Senders){
sender=s;
System.out.println("接收方开始接收分组数据!
");
}
voidreceive(intdata,Senders){
sender=s;//发送方的参数传递
System.out.println("接收方收到了序号为"+data+"的分组!
");
if(data!
=0){
if(data==lastdata+1){
//数据包序号校验,若连续则是正确/所期待的
System.out.println("该数据分组正是接收方所期待的,接收方接受了它并准备回送对应的ACK!
");
lastdata=data;//更新本地保存的数据包序号变量
respond(lastdata);//回送该正确接收的数据包对应的ACK
}
else{
System.out.println("该数据分组不是接收方所期待的,该分组将被丢弃,接收方准备回送最后接受的数据分组对应的ACK!
");
respond(lastdata);//若不是所期待的数据包则丢弃并且重发上一次的ACK
}
}
else{
System.out.println("该数据分组正是接收方所期待的,接收方接受了它并准备回送对应的ACK!
");
lastdata=data;
respond(lastdata);//首次接收数据包并且回送ACK
}
}
voidrespond(intack){//回送指定序号的ACK
if(sender.litime.limit<20){//判断是否超时(2秒)
ack=lastdata;//获取本场保存的数据包序号
sender.getack(ack);
}
else{
System.out.println("计时超时!
!
(未丢包但是时间超过2秒)发送方准备重发序号为"+ack+"的数据分组!
");
sender.switches=1;//如果超时,设置超时状态并显示警告
}
}
}
(三)Timers类
importjava.util.TimerTask;
publicclassTimersextendsTimerTask{
publicintswitches;
publicintlimit;
publicvoidrun(){
if(limit<20)limit++;//计时2秒
else{
switches=-1;
this.cancel();
}//开关为-1表示超时,并且停止计时器
}
publicTimers(){
switches=0;//启动计时器时全部初始化
limit=0;
}
}
(四)GBN类
import.*;
importjava.util.Random;
importjava.io.*;
publicclassGBNextendsThread{
staticvoidsenddelay(intx)throwsInterruptedException{
if(x==1){sleep(300);System.out.println("发送数据分组时发生延迟:
300毫秒!
");}
elseif(x==2){sleep(750);System.out.println("发送数据分组时发生延迟:
750毫秒!
");}
elseif(x==3){sleep(1200);System.out.println("发送数据分组时发生延迟:
1200毫秒!
");}
elseif(x==4){sleep(3000);System.out.println("发送数据分组时发生延迟:
3000毫秒!
");}
else;
}
publicstaticvoidmain(String[]args)throwsIOException,InterruptedException{
Senders=newSender();
Receiverre=newReceiver();
s.start();//发送端启动
re.run(s);//接收端启动
sleep(1000);//延迟处理
int[]retimes=newint[7];//计算每个分组被发送的次数
for(inti=0;i<7;i++)retimes[i]=0;//数据包顺次发送
for(inti=0;i<=s.sign.length;i++){
while(i>s.localack+1){//尚有未确认的数据包,重发!
System.out.println("发送方开始重新发送序号为"+(s.localack+1)+"的数据分组");
retimes[s.localack+1]++;
intran=newRandom().nextInt(3);
intrandelay=newRandom().nextInt(5);
s.time();
senddelay(randelay);//设置随机值,模拟数据传输延迟
if(ran!
=1)re.receive(s.localack+1,s);//设置随机值,模拟数据丢包过程
elseSystem.out.println("序号为"+(s.localack+1)+"的分组在传给接收方途中发生了丢包!
");
}
if(i!
=s.sign.length){
System.out.println();
System.out.println("发送方现在开始第一次发送序号为"+i+"的数据分组");
retimes[i]++;
if(i!
=0){
for(intk=0;k<3;k++){//表示至少成功发送并确认了一个数据分组
s.windowsign[k]++;//这种情况下滑动窗口向前移动!
}
}
System.out.println();
System.out.println("当前窗口内的分组情况为:
");//显示当前窗口内数据包情况
for(intp=0;p<3;p++){
if(s.windowsign[p]<=6)
System.out.println("第"+p+"号窗口里面存放的是序号为"+s.windowsign[p]+"的马上待发送的数据分组!
");
else
System.out.println("第"+p+"号窗口已经空了,并且后续窗口、发送方没有要发送的数据分组了!
");
}
System.out.println();
intran=newRandom().nextInt(3);
intrandelay=newRandom().nextInt(5);
s.time();//计时开始(2秒时间)
senddelay(randelay);//设置随机值,模拟数据传输延迟
if(ran!
=1)re.receive(s.sign[i],s);//设置随机值,模拟数据丢包过程
elseSystem.out.println("序号为"+i+"的分组在传给接收方途中发生了丢包!
");
}
}
System.out.println();System.out.println("以下是每个数据分组被发送过的次数的统计结果");
for(inti=0;i<7;i++)//显示关于每个数据包发送次数的统计表
System.out.println("序号为"+i+"的数据分组被发送过的次数为:
"+retimes[i]);
System.exit(0);
}
}
8.程序运行结果部分截图
PS:
随机选择了某次程序运行后结果显示的部分截图