编程实现可靠数据传输原理Go-Back-N

        有一个计算机网络的实验,需要模拟GBN的过程,即在本地条件下模拟丢包重传机制。刚看到这个实验时有些不知所措,因为不知道怎样能实现丢包,在本地编程,即使是使用不可靠数据传输UDP的DatagramSocket,由于localhost到localhost走的是回环链路,也就是从客户机的应用层--传输层--网络层 到 服务器的网络层--传输层--应用层,这个肯定无法丢包,也用实验进行验证了(比如连续发送1万个DatagramPacket,发现每一个都被收到了)。

        那么问题来了,怎样才能丢包?

        通过前面的叙述,可知在链路上丢包是不可能的了,那我们可以从服务器端下手,也就是说,即使服务器收到了某个数据包,也不给客户机发ACK,那么到了客户机设置的定时器后,客户机自然就认为是丢包了。所以可以给服务器设置一个丢包概率,用Math.random()函数来实现,该函数返回一个从0到1之间的随机数,可用来设置“丢包”概率。如设置丢包概率为0.3:

if (Math.random()<=0.7){ 
    //接收成功,发ack; 
}else{
    //呵呵,什么都不做
}


        “丢包”问题解决了,下面就是怎么发送数据包,用之前学过的TCP的Socket也行,用UDP的DatagramSocket也行,这个实验就采用UDP编程吧,所以,下一个问题就是,如何用UDP编程。

        同样也需要Socket(不理解Socket是什么的可以看前几篇文章),不过这次的是DatagramSocket,代表是UDP的数据报套接字。DatagramSocket要往外发送数据包,也就是DatagramPacket。举一个客户机可以向服务器发送数据并在服务器显示的例子。

        客户端代码如下:

public class UDPClient { 
    public static void main(String[] args) throws Exception { 
        //创建UDP的socket 
        DatagramSocket socket = new DatagramSocket(); 
        //通过域名来获得服务器的IP地址 
        InetAddress serverAddress = InetAddress.getByName("localhost"); 
        String str = "Hello Server, I am client"; 
        //需要将发送的字符串转换成字节数组,才能在互联网中传输 
        byte[] data = str.getBytes(); 
        //新建数据包,指明发送数据内容,发送的长度,服务器地址,服务器端口号 
        DatagramPacket packet = new DatagramPacket(data, data.length, 
                serverAddress, 8899); 
        //使用socket发送数据包 
        socket.send(packet); 
    } 
}

 

        对应服务器端代码如下:

public class UDPServer { 
    public static void main(String[] args) throws Exception { 
        //新建服务器端socket,并同时设置监听端口 
        DatagramSocket socket = new DatagramSocket(8899); 
        while (true){ 
            byte[] data = new byte[1024]; 
            //新建数据包,会把后面收到的内容放到data字节数组里,最大长度为data.length 
            DatagramPacket packet = new DatagramPacket(data, data.length); 
            //此方法为阻塞方法(block method),直到监听到数据包后才会往下执行,不然就一直等待,就像ServerSocket.accept()方法一样 
            socket.receive(packet); 
            //执行到这里说明监听到了数据包,并把其中内容转换为字符串 
            String result = new String(packet.getData()); 
            //打印 
            System.out.println("receive result : " + result); 
        } 
    } 
}

       

         务必先运行服务器端,再运行客户端。运行结果如下:


       

         若想服务器端给客户端发送数据,可同样操作。

 

        利用DatagramSocket发送DatagramPacket的问题解决了,那么下一个问题,在GBN协议里面,客户端发送一个数据之后要设置定时器的,这个定时器怎么设置?

        在java里有两种方式来设置定时器,首先是第一种方法,使用Timer结合ActionListener即可。

        代码如下,其中值得注意的一点是Timer要导入java.swing这个包中的,而不是java.util这个包中的,否则不能正确运行。

import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener;
import javax.swing.Timer;
public class TimerMain { 
    public static void main(String[] args) { 
        //设置定时器,第一个参数为延迟执行时间,单位是毫秒;第二个参数为到时间后执行的动作,类型为ActionListener 
        Timer timer = new Timer(3000, new DelayActionListener()); 
        //这个必须写,才可以使得timer生效 
        timer.start(); 
        //为了不让程序结束,加个死循环,不然timer定时器还没到,主程序就结束了 
        while (true){ 
        } 
    } 
}
//自定义动作类实现ActionListener接口 
class DelayActionListener implements ActionListener{ 
    //此为回调方法,当时间到后自动执行actionPerformed方法 
    @Override 
    public void actionPerformed(ActionEvent e) { 
        System.out.println("定时器时间到"); 
    } 
}

        运行结果如下:每隔3秒执行一次。如果需要取消定时器,使用timer.stop()方法即可。


 

        设置定时器的第二种方法是使用Timer结合TimerTask,在android里很常用,其实本来就是java的东西,代码如下:

import java.util.Timer; 
import java.util.TimerTask;
public class TimerTaskMain { 
    public static void main(String[] args) { 
        //使用TimerTask 
        TimerTask timerTask = new TimerTask() { 
            @Override 
            public void run() { 
                System.out.println("timerTask定时器时间到"); 
            } 
        }; 
        Timer timer = new Timer(); 
        //第一个参数为要执行的目标,第二个参数为第一次执行延迟的时间,第三个参数为循环执行的时间间隔,单位都是毫秒 
        timer.schedule(timerTask, 3000, 3000); 
    } 
}

        运行结果如下:每隔3秒执行一次。如果需要取消定时器,使用timerTask.cancel()方法即可。


 

        有了如上这些东西,再结合GBN的原理和自己控制的逻辑操作,写GBN就应该可以实现了,就不贴完整代码了,自己实现印象更深刻些。


update--------


很多人跟我说你的 GBN 程序没源码。。。。虽然这里没贴源码,但我下面给了Github链接了,进去找找就好了,很明显的 GBN 开头的仓库就是了,一定要学会使用Github啊。。。方便的话帮我点几个`star`也好哈。


个人github:  http://github.com/icodeu
个人网站:www.icodeyou.com


  • 17
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
基于 go-back-n 的可靠数据传输是一种常见的数据传输协议,它通过设置滑动窗口和确认号来实现可靠传输。要实现这样的软件,我们可以运用不同的编程语言进行开发。 首先,我们可以使用C语言进行开发。通过C语言的网络编程库,我们可以方便地实现基于 go-back-n 的数据传输软件。我们可以使用套接字来建立与远程主机的连接,并使用滑动窗口机制来控制数据的发送和接收。同时,使用C语言还可以轻松地管理缓冲区、序列号和确认号等变量。 其次,我们可以使用Java语言进行开发。Java提供了丰富的网络编程库,例如Socket和DatagramSocket类,可以方便地进行网络通信。通过使用Java的多线程机制,我们可以同时发送和接收数据,实现并行传输。同时,Java的面向对象特性可以让我们更好地设计和实现滑动窗口、帧结构和数据包的处理。 另外,我们还可以使用Python语言进行开发。Python是一种简洁而强大的脚本语言,具有易于理解和编写的特点。通过使用Python的套接字库,我们可以快速实现基于 go-back-n 的数据传输软件。此外,Python还提供了多线程和异步编程的支持,可以进一步提高软件的性能和效率。 总之,无论选择哪种编程语言进行开发,实现基于 go-back-n 的可靠数据传输软件需要注意的关键点包括:建立连接、设置滑动窗口大小、处理超时和丢包、发送和接收确认以及处理丢失数据或重复数据等情况。在实现过程中,我们需要仔细考虑各种操作系统和网络环境下的稳定性和可靠性,并进行适当的错误处理和异常处理,确保数据传输可靠性和完整性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值