实验七、传输层可靠传输协议GBN编程实验报告序号:姓名:学号:成绩指导老师:一、实验目的:1、通过编写实现一个简单可靠的数据传输协议GBN的发送和接收代码,模拟可靠数据传输2、理解TCP协议可靠传输的差错检测、重传、累计确认、定时器的可靠传输策略。
二、实验原理:在GBN中,发送端不需要在接收到上一个数据包的ACK后才发送下一个数据包,而是可以连续发送数据包。
在发送端发送数据包的过程中,如果接收到对应已发送的某个数据包的NACK,则发送端将NACK对应的某个数据包进行重发,然后再将该数据包之后的数据包依次进行重发。
三、结果分析:本次试验中采用java语言进行程序编写代码注释:(一)S ender类import java.util.Timer;public class Sender extends Thread{public int windowsize=3; //发送方窗口长度设为3public String[] data={"data1","data2","data3","data4","data5","data6","data7"}; //模拟七个数据包public int sign[]={0,1,2,3,4,5,6}; //为7个数据包标号public int localack=-1; //保存最近收到的ACKpublic 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("发送方开始发送分组数据!");}public void getack(int ack){System.out.println("发送方收到了ACK,序号为"+ack+"并且开始加以确认!");if(ack!=localack+1){System.out.println("经验证,这不是发送方正期待的ACK,立刻重发序号为"+(localack+1)+"的数据分组!");acksign=1;}else{localack=ack; //表示正确确认了ACKacksign=0;}}public void time(){switches=0; //标志初始化为0litime=new Timers();Timer limit=new Timer();limit.schedule(litime, 0,100);}}(二)R eceiver类import java.util.Random;public class Receiver extends Thread{public int lastdata;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!=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 }}void respond(int ack){ //回送指定序号的ACK if(sender.litime.limit<20){ //判断是否超时(2秒)ack=lastdata; //获取本场保存的数据包序号sender.getack(ack);}else{System.out.println("计时超时!!(未丢包但是时间超过2秒)发送方准备重发序号为"+ack+"的数据分组!");sender.switches=1; //如果超时,设置超时状态并显示警告}}}(三)T imers类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;}}(四)G BN类import .*;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毫秒!");}else;}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]+"的马上待发送的数据分组!");elseSystem.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+"的分组在传给接收方途中发生了丢包!");}}System.out.println();System.out.println("以下是每个数据分组被发送过的次数的统计结果");for(int i=0;i<7;i++) //显示关于每个数据包发送次数的统计表System.out.println("序号为"+i+"的数据分组被发送过的次数为:"+retimes[i]);System.exit(0);}}结果截图:。