计算机网络原理——实验三编程实现可靠数据传输原理 Go-Back-N

 一.实验目的和意义

运用各种编程语言实现基于 Go-Back-N 的可靠数据传输软件。 通过本实验,使学生能够对可靠数据传输原理有进一步的理解和掌握。

二.实验背景:

Go-Back-N 的有限状态机模型表示如图 3.1 所示:

三.实验过程

1.选择合适的编程语言编程实现基于 Go-Back-N 的可靠数据传输软件。

2.在实际网络环境或模拟不可靠网络环境中测试和验证自己的可靠数据传输软 件。

(1)按照实验要求,编写实现不同功能的 java 文件。

文件名功能
Timers.java实现计时器功能,用于恢复数据或确认分组的丢失,这里计时 2s
Sender.java用于发送数据分组。这里确定发送窗口长度为 3,模拟 7 个数据包
Receiver.java用于接受数据分组,并发送相应的 ACK
GBN.java主函数,是整个程序的入口

(2)编译 java 文件。 我们使用 jdk 的 javac 指令对 java 代码进行编译,要注意的是我们有 4 个 java 文件,部分文 件类使用了其他文件中的类,要注意编译的顺序。

(3)实验结果 

 

 

 

四.实验分析和总结

1.遇到的问题

(1)找不到符号

类 GBN 会调用另一个类 Sender,不是独立的 java 文件,所以编译的话需要一起编译,或者 先编译类 Sender 再编译类 GBN。

(2)找不到或无法加载主类

在 idea 里面编写的 java 文件存在包名,即 package,这个 package 就相当于一个子路径。 在 运 行 java 文 件 时 , 必 须 带 上 包 名 。 比 如 , 上 图 所 示 代 码 D:\program\java\project\3_GBN>java Timers 应该为 D:\program\java\project\3_GBN>java GBN.Timers.

但后来发现本实验完全可以不加 package,遂将所有文件的 package 都删除。

2.收获与心得

本次实验中,我们完成了 java 的网络编程,模拟了 GBN 算法的运行,对 GBN 协议有了进一步的了解。 在 GBN 协议中,接收方会丢弃所有失序的分组,尽管丢弃一个正确接收但是失序的分组有 点浪费。但是根据 GBN 的原理。假定当前期望的编号是 n,但是 n+1 提前达到。因为数据 必须是有序交付,接收方可能缓存分组 n+1,然后在他收到并交付分组 n 后,再将该分组交 付到上层。但是如果 n 丢失,则 n 和 n+1 的分组都会被重发,因此,接收方只需要丢弃分 组 n+1 即可。

这种方法的优点是接收方缓存简单,即接收方不需要缓存任何失序分组。对于发送方来说, 他只需要维护窗口的下边界和和 nextseqnum 在窗口中的位置。对于接收方来说,只需要维 护下一个按序接收的分组的序号。

在本次实验中,我遇到了很多关于 java 语言编程的问题,主要是因为之前没有系统学习过 java,导致出现了很多较低级的错误,也耗费了很多时间,本次实验也加深了我对 java 语言 的学习,又提升了自己的编程语言能力!

五.代码附录

/*Timers.java*/
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(){
switches=0; //启动计时器时全部初始化
limit=0;
}
}
/*Sender.java*/
import java.util.Timer;
public class Sender extends Thread{
public int windowsize=3; //发送方窗口长度设为 3
public String[] data={"datal","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=0; //为 0 表示收到正确 ACK,为 1 表示收到错误的 ACK,必须重
发!
public Sender(){
windowsign=new int[windowsize]; //给窗口分配指定大小的空间
for(int i=0;i<3;i++)
windowsign[i]=sign[i]; //窗口初始化时存放前 3 个序号
}
public void run(){
System.out.println("\n==========发送方开始发送分组数据==========");
}
public void getack(int ack){
System.out.println("发送方收到了 ACK"+ack);
if(ack!=localack+1){
System.out.println("经验证,ACK"+ack+"不是发送方所期待的,重发数据分组
"+(localack+1));
acksign=1;
}else{
localack=ack;
acksign=0; //表示正确确认了 ACK
System.out.println("经验证,ACK"+ack+"是发送方所期待的");
}
}
public void time(){
switches=0; //标志初始化为 0
litime=new Timers();
Timer limit=new Timer();
limit.schedule(litime,0,100);
}
}
/*Receiver.java*/
public class Receiver extends Thread{
public int lastdata;
public Sender sender;
public void run(Sender s){
sender=s;
System.out.println("\n==========接收方开始接收分组数据==========");
}
void receive(int data, Sender s){
sender=s; //发送方的参数传递
System.out.println("\n========== 接 收 方 收 到 了 序 号 为 "+data+" 的 分 组
==========");
if(data!=0){
if(data==lastdata+1){ //数据包序号校验,若连续则是正确/所期待的
System.out.println("该数据分组"+data+"是接收方所期待的,接收方接受了
它并准备回送对应的 ACK");
lastdata=data; //更新本地保存的数据包序号变量
respond(lastdata); //回送该正确接收的数据包对应的 ACK
}
else{
System.out.println("该数据分组不是接收方所期待的,该分组将被丢弃,接
收方准备回送最后接受的数据分组对应的 ACK");
respond(lastdata);//若不是所期待的数据包则丢弃并且重发上一次的 ACK
}
}
else{
System.out.println("该数据分组"+data+"是接收方所期待的,接收方接受了它并
准备回送对应的 ACK");
lastdata=data;
respond(lastdata); //首次接受数据包并且回送 ACK
}
}
void respond(int ack){ //回送指定序号的 ACK
if(sender.litime.limit<20){
ack=lastdata; //判断是否超时(2 秒)
sender.getack(ack); //获取本场保存的数据包序号
}
else{
System.out.println("计时超时,未丢包但是时间超过 2 秒,发送方准备重发序号为
"+ack+"数据分组");
sender.switches=1;//如果超时,设置超时状态并显示警告
}
}
}
/*GBN.java*/
import java.net.*;
import java.util.Random;
import java.io.*;
public class GBN extends Thread{
static void senddelay(int x) throws InterruptedException{
if(x==1){
sleep(300);
System.out.println("发送数据分组时发生延迟:300 毫秒");
}
else if(x==2){
sleep(750);
System.out.println("发送数据分组时发生延迟:750 毫秒");
}
else if(x==3){
sleep(1200);
System.out.println("发送数据分组时发生延迟:1200 毫秒");
}
else if(x==4){
sleep(3000);
System.out.println("发送数据分组时发生延迟:3000 毫秒");
}
}
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;i++){
while(i>s.localack+1){ //尚有未确认的数据包,重发
System.out.println("发送方开始重新发送序号为"+(s.localack+1)+"的数据分
组");
retimes[s.localack+1]++;
int ran=new Random().nextInt(3);
int randelay=new Random().nextInt(5);
s.time();
senddelay(randelay);//设置随机值,模拟数据传输延迟
if(ran!=1)
re.receive(s.localack+1,s);//设置随机值,模拟数据丢包过程
else
System.out.println("序号为"+(s.localack+1)+"的分组在传给接收方途中发生
了丢包");
}
if(i!=s.sign.length){
System.out.println();
System.out.println("发送方现在开始第一次发送序号为"+i+"的数据分组");
retimes[i]++;
if(i!=0){
for(int k=0;k<3;k++){ //表示至少成功发送并确认了一个数据分组
s.windowsign[k]++; //这种情况下滑动窗口向前移动!
}
}
System.out.println();
System.out.println("当前窗口内的分组情况为:");//显示当前窗口内数据包情
况
for(int p=0;p<3;p++){
if(s.windowsign[p]<=6)
System.out.println(" 第 "+p+" 号 窗 口 里 面 存 放 的 是 序 号 为
"+s.windowsign[p]+"的即将待发送的数据分组");
else
System.out.println("第"+p+"号窗口为空,后续窗口发送方没有要
发送的数据分组");
}
System.out.println();
int ran=new Random().nextInt(3);
int randelay=new Random().nextInt(5);
s.time(); //计时开始 (2 秒时间)
senddelay(randelay); //设置随机值,模拟数据传输延迟
if(ran!=1) 
re.receive(s.sign[i],s);//设置随机值,模拟数据丢包过程
else 
System.out.println("序号为"+i+"的分组在传给接收方途中发生了丢包
");
}//if 语句结束
}//for 循环结束
System.out.println();
System.out.println("========== 统计每个数据分组被发送过的次数
==========");
for(int i=0;i<7;i++){ //显示关于每个数据包发送次数的统计表
System.out.println("序号为"+i+"的数据分组被发送过"+retimes[i]+"次");
}
System.exit(0);
}
}

写在最后:因为林过雨,所以想为学弟学妹们撑起一把伞,计算机网络这门折磨人的课终于结束了,以上都是当时写作业时在网上搜搜找找拼凑出来的实验报告,仅代表个人的作业,不保证正确性啊哈。而且因为是从自己的pdf作业整理出来的,有些部分显得非常丑

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值