项目目录:
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"); //收到base的ACK 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; } }