计算机网络实验,JAVA实现一个简单GBN、SR协议,模拟引入数据包的丢失,验证协议的有效性

项目目录:

 

GBNClient类(GBN协议数据发送端)

package gbn;

import timerPackage.Model;
import timerPackage.Timer;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/**
 * 客户端
 */
public class GBNClient {
    private final int port = 80;
    private DatagramSocket datagramSocket = new DatagramSocket();
    private DatagramPacket datagramPacket;
    private InetAddress inetAddress;
    private Model model;
    private static GBNClient gbnClient;
    private Timer timer;
    private int nextSeq = 1;
    private int base = 1;
    private int N = 5;


    public GBNClient() throws Exception {
        model = new Model();
        timer = new Timer(this,model);
        model.setTime(0);
        timer.start();
        while(true){
            //向服务器端发送数据
            sendData();
            //从服务器端接受ACK
            byte[] bytes = new byte[4096];
            datagramPacket = new DatagramPacket(bytes, bytes.length);
            datagramSocket.receive(datagramPacket);
            String fromServer = new String(bytes, 0, bytes.length);
            int ack = Integer.parseInt(fromServer.substring(fromServer.indexOf("ack:")+4).trim());
            base = ack+1;
            if(base == nextSeq){
                //停止计时器
                model.setTime(0);
            }else {
                //开始计时器
                model.setTime(3);
            }
            System.out.println("从服务器获得的数据:" + fromServer);
            System.out.println("\n");
        }

    }

    public static void main(String[] args) throws Exception {
         gbnClient = new GBNClient();

    }

    /**
     * 向服务器发送数据
     *
     * @throws Exception
     */
    private void sendData() throws Exception {
        inetAddress = InetAddress.getLocalHost();
        while (nextSeq < base + N && nextSeq <= 10) {
            //不发编号为3的数据,模拟数据丢失
            if(nextSeq == 3) {
                nextSeq++;
                continue;
            }

            String clientData = "客户端发送的数据编号:" + nextSeq;
            System.out.println("向服务器发送的数据:"+nextSeq);

            byte[] data = clientData.getBytes();
            DatagramPacket datagramPacket = new DatagramPacket(data, data.length, inetAddress, port);
            datagramSocket.send(datagramPacket);

            if(nextSeq == base){
               //开始计时
                model.setTime(3);
            }
            nextSeq++;
        }
    }

    /**
     * 超时数据重传
     */
    public void timeOut() throws Exception {
        for(int i = base;i < nextSeq;i++){
            String clientData = "客户端重新发送的数据编号:" + i;
            System.out.println("向服务器重新发送的数据:" + i);
            byte[] data = clientData.getBytes();
            DatagramPacket datagramPacket = new DatagramPacket(data, data.length, inetAddress, port);
            datagramSocket.send(datagramPacket);
        }
    }
}

GBNServer类(GBN协议数据接收端)

package gbn;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

/**
 * 服务器端
 */
public class GBNServer {
    private final int port = 80;
    private DatagramSocket datagramSocket;
    private DatagramPacket datagramPacket;
    private int exceptedSeq = 1;

    public GBNServer() throws IOException {

            try {
                datagramSocket = new DatagramSocket(port);
                while (true) {
                    byte[] receivedData = new byte[4096];
                    datagramPacket = new DatagramPacket(receivedData, receivedData.length);
                    datagramSocket.receive(datagramPacket);
                    //收到的数据
                    String received = new String(receivedData, 0, receivedData.length);//offset是初始偏移量
                    System.out.println(received);
                    //收到了预期的数据
                    if (Integer.parseInt(received.substring(received.indexOf("编号:") + 3).trim()) == exceptedSeq) {
                        //发送ack
                        sendAck(exceptedSeq);
                        System.out.println("服务端期待的数据编号:" + exceptedSeq);
                        //期待值加1
                        exceptedSeq++;
                        System.out.println('\n');
                    } else {
                        System.out.println("服务端期待的数据编号:" + exceptedSeq);
                        System.out.println("+++++++++++++++++++++未收到预期数据+++++++++++++++++++++");
                        //仍发送之前的ack
                        sendAck(exceptedSeq - 1);
                        System.out.println('\n');
                    }
                }
            }catch(SocketException e){
                    e.printStackTrace();
                }
        }

    public static final void main(String[] args) throws IOException {
        new GBNServer();
    }

    //向客户端发送ack
    public void sendAck(int ack) throws IOException {
        String response = " ack:"+ack;
        byte[] responseData = response.getBytes();
        InetAddress responseAddress = datagramPacket.getAddress();
        int responsePort = datagramPacket.getPort();
        datagramPacket = new DatagramPacket(responseData,responseData.length,responseAddress,responsePort);
        datagramSocket.send(datagramPacket);
    }
}

  SRClient类(SR协议数据发送端

package sr;

import timerPackage.Model;
import timerPackage.Timer;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class SRClient {
    //共用端口号
    private final int port = 80;
    //发送的数据的数量
    private final int num = 10;
    private DatagramSocket datagramSocket = new DatagramSocket();
    private DatagramPacket datagramPacket;
    private InetAddress inetAddress;
    private Model model;
    private static SRClient srClient;
    private Timer timer;
    private int nextSeq = 1;
    private int base = 1;
    private boolean[] mark;
    private int N = 5;


    public SRClient() throws Exception {
        mark = new boolean[num+1];
        model = new Model();
        timer = new Timer(this,model);
        model.setTime(0);
        timer.start();
        while(true){
            //向服务器端发送数据
            sendData();
            //从服务器端接受ACK
            byte[] bytes = new byte[4096];
            datagramPacket = new DatagramPacket(bytes, bytes.length);
            datagramSocket.receive(datagramPacket);

            String fromServer = new String(bytes, 0, bytes.length);
            int ack = Integer.parseInt(fromServer.substring(fromServer.indexOf("ack:")+4).trim());
            mark[ack] = true;
            System.out.println("从服务器获得的数据:" + fromServer);
            System.out.println("\n");

            //收到baseACK
            if(base == ack && base != num){
                base++;
                //乱序之后,把base值移到最远的位置
                for(int i = base; i < nextSeq;i++){
                    if(mark[i] == true){
                        base = i + 1;
                    }
                }
            }else if(base == ack && base == num){
                timer.interrupt();
                sendEnd();
                break;
            }

            if(base == nextSeq){
                //停止计时器
                model.setTime(3);
            }else {
                //开始计时器
                model.setTime(0);
            }
        }
    }

    public static void main(String[] args) throws Exception {
        srClient = new SRClient();
    }

    /**
     * 向服务器发送数据
     *
     * @throws Exception
     */
    private void sendData() throws Exception {
        inetAddress = InetAddress.getLocalHost();
        while (nextSeq < base + N && nextSeq <= num) {
            //不发编号为3的数据
            if(nextSeq == 3) {
                nextSeq++;
                continue;
            }

            String clientData = "客户端发送的数据编号:" + nextSeq;
            System.out.println("向服务器发送的数据:"+nextSeq);

            byte[] data = clientData.getBytes();
            DatagramPacket datagramPacket = new DatagramPacket(data, data.length, inetAddress, port);
            datagramSocket.send(datagramPacket);

            if(nextSeq == base){
                //开始计时
                model.setTime(3);
            }
            nextSeq++;
        }
    }

    /**
     * 超时数据重传,仅重传base     */
    public void timeOut() throws Exception {
            String clientData = "客户端重新发送的数据编号:" + base;
            System.out.println("向服务器重新发送的数据:" + base);
            byte[] data = clientData.getBytes();
            DatagramPacket datagramPacket = new DatagramPacket(data, data.length, inetAddress, port);
            datagramSocket.send(datagramPacket);
    }

    /**
     * 向服务器发送结束信号
     */
    public void sendEnd() throws IOException {
        inetAddress = InetAddress.getLocalHost();
        int end = -1;
            String clientData = "客户端发送的数据编号:" + end;
            System.out.println("向服务器发送结束信号");

            byte[] data = clientData.getBytes();
            DatagramPacket datagramPacket = new DatagramPacket(data, data.length, inetAddress, port);
            datagramSocket.send(datagramPacket);
        }
    }
 
 

 

SRServer类(SR协议数据接收端)

package sr;


import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.ArrayDeque;
import java.util.Queue;

public class SRServer {
    //共用端口号
    private final int port = 80;
    //窗口大小
    private final int N = 3;
    private DatagramSocket datagramSocket;
    private DatagramPacket datagramPacket;
    private int exceptedSeq = 1;
    //缓存队列
    private Queue<Integer> cache = new ArrayDeque<>();

    public SRServer() throws IOException {
        try {
            datagramSocket = new DatagramSocket(port);
            while (true) {
                byte[] receivedData = new byte[4096];
                datagramPacket = new DatagramPacket(receivedData, receivedData.length);
                datagramSocket.receive(datagramPacket);

                //收到的数据
                String received = new String(receivedData, 0, receivedData.length);//offset是初始偏移量
                System.out.println(received);
                int ack = Integer.parseInt(received.substring(received.indexOf("编号:") + 3).trim());
                if(ack == -1){
                    System.out.println("本次传输结束");
                    break;
                }else{
                    sendAck(ack);

                    //收到了预期的数据
                    if (ack == exceptedSeq) {
                        System.out.println("服务端期待的数据编号:" + exceptedSeq);
                        //期待值加1
                        exceptedSeq++;
                        //滑动窗口到最大值
                        while( cache.peek() != null && cache.peek()== exceptedSeq){
                            System.out.println("从服务器端缓存中读出数据:"+cache.element());
                            cache.poll();
                            exceptedSeq++;
                        }

                        System.out.println('\n');
                    } else {
                        System.out.println("服务端期待的数据编号:" + exceptedSeq);
                        System.out.println("+++++++++++++++++++++未收到预期数据+++++++++++++++++++++");
                        cache.add(ack);
                        System.out.println('\n');
                    }
                }
            }
        }catch(SocketException e){
            e.printStackTrace();
        }
    }

    public static final void main(String[] args) throws IOException {
        new SRServer();
    }

    //向客户端发送ack
    public void sendAck(int ack) throws IOException {
        String response = " ack:"+ack;
        byte[] responseData = response.getBytes();
        InetAddress responseAddress = datagramPacket.getAddress();
        int responsePort = datagramPacket.getPort();
        datagramPacket = new DatagramPacket(responseData,responseData.length,responseAddress,responsePort);
        datagramSocket.send(datagramPacket);
    }
}

Timer类(计时器)

package timerPackage;

import gbn.GBNClient;
import sr.SRClient;

/**
 * 计时器
 */
public class Timer extends Thread {

    private Model model;
    private GBNClient gbnClient;
    private SRClient srClient;
    public Timer(GBNClient gbnClient, Model model){
        this.gbnClient = gbnClient;
        this.model = model;
    }
    public Timer(SRClient srClient,Model model){
        this.srClient = srClient;
        this.model = model;
    }
    @Override
    public void run(){
        do{
            int time = model.getTime();
            if(time > 0){
                try {
                    Thread.sleep(time*1000);

                    System.out.println("\n");
                    if(gbnClient == null){
                        System.out.println("SR客户端等待ACK超时");
                        srClient.timeOut();
                    }else{
                        System.out.println("GBN客户端等待ACK超时");
                        gbnClient.timeOut();
                    }
                    model.setTime(0);

                } catch (InterruptedException e) {
                } catch (Exception e) {
                }
            }
        }while (true);
    }
}

Model类

package timerPackage;

/**
 * 保证线程安全性
 */
public class Model {

    public volatile int time;

    public  synchronized int getTime() {
        return time;
    }

    public synchronized void setTime(int time) {
        this.time = time;
    }
}

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值