首页 > 编程语言 >编程实现可靠数据传输原理 Go-Back-N

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

时间:2023-04-25 20:33:42浏览次数:32  
标签:String int Back packet static new Go 数据传输 public

1. 编写接收端代码

接收端模拟网络环境较差时情况,每次生成一个随机数,小于0.8时不丢包,大于0.8时丢包。

接收数据格式:编号+空格+内容

返回数据格式:

丢包:Loss+空格+编号

未丢包:ACK+空格+编号

接收包非累计计数时不做处理。

2. 编写发送端代码

发送端较为复杂,分为两个线程:

发送线程:

设置窗口大小为5,当超过窗口时死循环,停止发送;

处理线程:

判断是否ACK,如果累计增加,窗口向右滑动一格,否则重发;

另设置20个定时器,如果超过5秒未响应,则重发。

理论上来说5个定时器就够了,但懒得改了(

Receiver代码:

import java.net.*;
public class Receiver {
    public static int send_port = 8899;
    public static int receive_port = 8848;
    public static void main(String[] args) throws Exception {
        InetAddress serverAddress = InetAddress.getByName("localhost");
        DatagramSocket socket = new DatagramSocket(receive_port);
        int cnt=0;
        while (true){
            byte[] data = new byte[1024];
            DatagramPacket packet = new DatagramPacket(data, data.length);
            //此方法为阻塞方法
            socket.receive(packet);
            String r = new String(packet.getData(),0, packet.getLength());
            String[] result = r.split(" ",2);
            int num=Integer.parseInt(result[0]);
            if(Math.random()<0.8){
                //ack
                if(num==cnt){
                    String str = "ACK "+cnt;
                    byte[] res = str.getBytes();
                    DatagramPacket resp = new DatagramPacket(res, res.length,
                            serverAddress, send_port);
                    socket.send(resp);
                    System.out.println("receive result : " + result[1]);
                    cnt++;
                }
                else{
                    System.out.println("Discard packet "+num);
                }
            }
            else{
                //loss
                String str = "Loss "+num;
                byte[] res = str.getBytes();
                DatagramPacket resp = new DatagramPacket(res, res.length,
                        serverAddress, send_port);
                socket.send(resp);
                System.out.println("Loss : "+num);
            }

        }
    }
}
View Code

Client代码:

import javax.swing.Timer;
import java.io.IOException;
import java.net.*;

class Sender {
    //assume that the length of window is 5
    public static volatile int l=0;
    public static volatile int r=4;
    public static volatile int current=0;
    public static DatagramSocket socket;
    public static InetAddress serverAddress;
    public static int receive_port = 8848;
    public static Timer[] timers;
    public static String[] str;

    Sender(DatagramSocket s,InetAddress in){
        socket=s;
        serverAddress=in;
        str = new String[20];
        for(int i=0;i<20;i++){
            str[i]=i+" "+"Here is packet"+i;
        }
        timers = new Timer[20];
        for(int i=0;i<str.length;i++){
            int finalI = i;
            timers[i] = new Timer(5000, e -> {
                send(str[finalI]);
                System.out.println("Resend packet "+finalI);
                timers[finalI].restart();
            });
        }
    }

    public static void send(String s) {
        try {
            byte[] data = s.getBytes();
            DatagramPacket packet = new DatagramPacket(data, data.length,
                    serverAddress, receive_port);
            socket.send(packet);
        }
        catch (Exception e){
            System.out.println(e.getMessage());
        }

    }

    class SendPackage implements Runnable {
        @Override
        public void run(){
            for(int i=0;i<str.length;i++){
                send(str[i]);
                timers[i].start();
                current=i;
                while(current==r);
            }
        }
    }

    class DealMessage implements Runnable{

        @Override
        public void run() {
            while(l<str.length){
                byte[] rec = new byte[1024];
                DatagramPacket recp = new DatagramPacket(rec, rec.length);
                //此方法为阻塞方法
                try {
                    socket.receive(recp);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                String res = new String(recp.getData(),0, recp.getLength());
                System.out.println(res);
                String[] result=res.split(" ",2);
                int num=Integer.parseInt(result[1]);
                if(result[0].equals("ACK")){
                    if(num==l){
                        timers[num].stop();
                        l++;
                        System.out.println("Packet "+num+" has been received.");
                        r++;
                    }
                }
                else if(result[0].equals("Loss")){
                    System.out.println("Loss!Ready to send packet "+num+" again.");
                }
            }
        }
    }
}

public class Client {
    public static void main(String[] args) throws Exception {
        DatagramSocket socket = new DatagramSocket(8899);
        InetAddress serverAddress = InetAddress.getByName("localhost");
        Sender sender = new Sender(socket,serverAddress);

        Sender.DealMessage dealMessage = sender.new DealMessage();
        Thread t1=new Thread(dealMessage);
        t1.start();
        Sender.SendPackage sendPackage = sender.new SendPackage();
        Thread t2=new Thread(sendPackage);
        t2.start();
    }
}
View Code

 

标签:String,int,Back,packet,static,new,Go,数据传输,public
From: https://www.cnblogs.com/capterlliar/p/17353752.html

相关文章

  • Django之路由层 (有名和无名分组 反向解析 路由分发 名称空间)
    目录一、路由匹配django2.X及以上path第一个参数写什么就匹配什么django1.X第一个参数是正则表达式PS:无论什么版本django都自带加斜杠后缀的功能也可以取消,这里如果在浏览器地址栏没有写完整的/index/,而是/index,这里还是可以找到的,因为Django会帮你二次查找,浏览器会有303......
  • Go
    今日内容1go语言变量类型#数字#int整数有正负int8int16int32int64 java byteshortintlong -int8一个字节表示(8个比特位)范围:-2的7次方到+2的7次方-1-int162个字节表范围:-2的15次方到+2的15次方-1-同理以此类推......
  • go语言变量类型、常量、函数基础、函数高级
    目录1go语言变量类型2常量3函数基础4函数高级1go语言变量类型#数字#int整数有正负int8int16int32int64 java byteshortintlong -int8一个字节表示(8个比特位)范围:-2的7次方到+2的7次方-1-int162个字节表范围:-2的15次方......
  • go语言time.Timer
    go语言time.TimerTimer是一个一次性的定时器,经过指定的时间后将会触发一个时间,通知调用的goroutine使用方法funcmain(){ timer:=time.NewTimer(3*time.Second) for{ select{ caset:=<-timer.C: fmt.Println(t) return } }}数据结构Timer//The......
  • 3 go语言变量类型
    目录3go语言变量类型1数字1.1int、int8、int16、int32、int641.2uint、uint8、uint16、uint32、uint641.3浮点型1.4复数1.5byte和rune2字符串3布尔类型4常量5iota常量生成器(1)定义规则6语句块、可见规则、作用域范围6.1语句块6.2可见行规则6.3作用域范围(1)全局变量(2......
  • Django框架——路由分发、名称空间、虚拟环境、视图层三板斧、JsonResponse对象、requ
    路由分发#Django支持每个应用都可以有自己独立的路由层、静态文件、模版层。基于该特性多人开发项目就可以完全解耦合,之后利用路由分发还可以整合到一起多个应用都有很多路由与视图函数的对应关系这个时候可以拆分到各自的路由层中使用路由分发之前总路由直接是路由与视图......
  • golang 中通过strings/bytes/bufio 等包实现相关IO
    在go的IO中,除了io、os等包,我们还有strings、bytes、bufio等实现IO读写,这其中有些实现了io.Reader,有些同时实现了io.Reader和io.Writer接口。接下来我们一个个看相关的使用。1.strings在strings包中,只实现了Reader,我们看看其代码://实现的readertypeRea......
  • go语言入门
    go语言入门go简介go语言,golang,是谷歌公司开发的,是编译型语言。编译型语言,需要将go代码编译成可执行文件,然后就可以在相应的系统上跑了,而开发环境中,我们需要下载gosdk,这个是go管理代码资源的工具,我们可以通过gobuild命令来编译go代码,gorun来编译+运行go代码(编译的代码即用即......
  • backpressure 背压介绍
    当数据流启动时,源就开始把一行行数据填到一个类似桶的缓存(buffer)中。源根本不知道下游是什么。一旦缓存满了,桶就随着流水线流到下游组件(component)上,同时引擎抓一个新的空缓存过来给源。源根本不知道这一切,它只是不断地填桶。有时源填了太多的桶,转换和端都来不及应付了;此时引擎会......
  • django打包成whl包并分发
    django打包成whl包并分发python中下载setuptools工具,打包成whl包结构公司内部写的包,只给公司内部使用,可以开源出来公司写好的项目,打包好,发送给客户,客户可以直接运行起来,不需要下载依赖注意:之前下载的第三包都是:requests-2.28.2-py3-none-any.whlwhl结尾的打包好的包,可以......