0

我正在尝试通过 UDP 实现 GBN 协议,窗口大小 = 5。我的代码如下:

客户:

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;


public class Sender {
    
    private static final int BUFFER_SIZE = 1024;
    private static final int PORT = 166;
    private static final String HOSTNAME = "localhost";
    private static final int WINDOW_SIZE = 5;
    
    static int sendBase = 1;
    static int nextSeqNum = 1;

    
    static byte[] sendData = new byte[1024];
    static byte[] receiveData = new byte[1024];

    public static void main(String args[]) throws Exception
    {
        DatagramSocket clientSocket = new DatagramSocket();
        clientSocket.setSoTimeout( 1000 );
        InetAddress IPAddress = InetAddress.getByName( HOSTNAME );
            
        while (true) {
            
            try {
                     if (nextSeqNum < sendBase + WINDOW_SIZE && nextSeqNum <= 15) {
                
                        // file reader for .txt file
                        FileReader fr = new FileReader("umbrella.txt");
                        BufferedReader br = new BufferedReader(fr);
                        String fileText = br.readLine();
                        
                        byte [] fileBytes = fileText.getBytes();
                        
                        //concatenate sequence number with file:
                        ByteArrayOutputStream outputStream = new ByteArrayOutputStream( );
                        DataOutputStream dos = new DataOutputStream(outputStream);
                        dos.writeInt(nextSeqNum);
                        dos.write(fileBytes);
                        
                        byte [] concatData = outputStream.toByteArray( );
                        
                        sendData = concatData;
                        
                        // create a datagramPacket
                        
                        DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, PORT);
                
                        // send the packet
                        clientSocket.send(sendPacket);
                        
                        nextSeqNum++;
                       
                        } // end of if
                 
                        
                        DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
                        clientSocket.receive(receivePacket);
                
                        String response = new String(receivePacket.getData());
                        response = response.trim();
                        
                        ByteArrayInputStream bais = new ByteArrayInputStream(receiveData);
                        DataInputStream dis = new DataInputStream(bais);
                        int rcvSN = dis.readInt();
    
                        // Print response if ack received from server
                            
                        System.out.println("Cumulative Ack received for Packet(s) up to and including " + rcvSN);
                        
                        sendBase = rcvSN +1;
                        
                        if (nextSeqNum > 15) {
                            
                            break;
                        }
                        
                    
            } catch ( SocketTimeoutException exception ) { // if timeout occurs resend from base
                
                        // If we don't get any ack, reset to last ack SN
                        System.out.println( "Timeout occurred, at sequence number: " + sendBase + " retransmitting from Seq: " + sendBase);
                        
                        nextSeqNum = sendBase;
                        
                        } // end of try and catch
                
                 
        } // end of while loop
        
        clientSocket.close(); // close socket to incoming
        
    } // end of main
} // end of class
    

服务器:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Random;

public class Receiver {
    
    private static final int BUFFER_SIZE = 1024;
    private static final int PORT = 166;
    
    public static void main(String args[]) throws Exception
    {
        
        DatagramSocket serverSocket = new DatagramSocket( PORT ); // set the server to listen on PORT
        byte[] receiveData = new byte[ BUFFER_SIZE ]; // byte array for incoming data
        byte[] sendData = new byte[ BUFFER_SIZE ]; // byte array for outgoing data
        int nextSeqNum = 1;
        String ack = "ACK";
        
        System.out.println("\nSERVER RUNNING...\n"); // notification of server listening
        
        while(true) { // while listening do:
            
            // Construct the datagram packet to receive the packet from the Client:
            DatagramPacket receivePacket = new DatagramPacket(receiveData,
            receiveData.length);
            serverSocket.receive(receivePacket); // receive it to the assigned server socket
            
            // Input stream to read the sequence number attached to a packet:
            ByteArrayInputStream bais = new ByteArrayInputStream(receiveData);
            DataInputStream dis = new DataInputStream(bais);
            int rcvSN = dis.readInt();
            
            String sentence = new String(receivePacket.getData()); // the sentence contained in the packet (from our file)
            
            System.out.println("Data received = " + sentence + " ... with sequence number: " + rcvSN);
            
                
                if (rcvSN == nextSeqNum) {
                    
    
                    if( new Random().nextDouble() <= 0.80 ) { // 80% of the time a received packet will send an ACK (for demo purposes)
                        
                    //send response stating receipt of in order packet
                    InetAddress IPAddress = receivePacket.getAddress(); 
                    int sendToPort = receivePacket.getPort(); // get port number of client
                        
                    ByteArrayOutputStream outputStream = new ByteArrayOutputStream( );
                    DataOutputStream dos = new DataOutputStream(outputStream);
                    dos.writeInt(rcvSN);
                    dos.write( ack.getBytes() );
                    
                    byte [] concatData = outputStream.toByteArray( );
                    
                    sendData = concatData;
                    DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, sendToPort); //construct packet
                    serverSocket.send(sendPacket); //send ACK
                    
                    nextSeqNum++;
                    }
                    
                } else {
                
                    System.out.println("Packets received out of order, resending ACK for last received: " + (rcvSN-1));
                    
                    //send response with last in order sequence number (resend last ACK)
                    InetAddress IPAddress = receivePacket.getAddress(); 
                    int sendToPort = receivePacket.getPort(); // get port number of client
                        
                    ByteArrayOutputStream outputStream = new ByteArrayOutputStream( );
                    DataOutputStream dos = new DataOutputStream(outputStream);
                    dos.writeInt(nextSeqNum - 1);
                    dos.write( ack.getBytes() );
                    
                    byte [] concatData = outputStream.toByteArray( );
                    
                    sendData = concatData;
                    DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, sendToPort); //construct packet
                    serverSocket.send(sendPacket); //resend ACK
                }
        
        
      }
    }
}

我的问题是,当我运行这个程序时,任何没有收到 ACK 的数据包都会立即重新传输(服务器超时,客户端再次发送丢失的数据包),如下所示:

收到的数据包的累积确认,最多 1 个(包括 1 个)

收到的数据包累积确认,最多 2 个(包括 2 个)

发生超时,在序列号:3 从 Seq 重新传输:3

收到的数据包的累积确认,最多 3 个(包括 3 个)

收到的数据包的累积确认,最多包括 4 .....

我希望客户端继续发送窗口中的所有数据包,服务器发送 ACK 消息,说明最后一个顺序序列号,直到整​​个窗口大小......

即,如果我们丢失了nextSeqNum= 2 id 的数据包,则希望服务器接收所有数据包 1-5,但重复声明最后一个 ACK​​ num 为 1:

收到的数据包的累积确认,最多 1 个(包括 1 个)

收到的数据包的累积确认,最多 1 个(包括 1 个)

收到的数据包的累积确认,最多 1 个(包括 1 个)

收到的数据包的累积确认,最多 1 个(包括 1 个)

收到的数据包的累积确认,最多 1 个(包括 1 个)

收到的数据包的累积确认,最多 1 个(包括 1 个)

收到的数据包的累积确认,包括 2 .....

我看到我需要catch等到窗口中的所有内容都发送完毕后再实现,但我不知道该怎么做。

4

0 回答 0