我正在尝试通过 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
等到窗口中的所有内容都发送完毕后再实现,但我不知道该怎么做。