我是编程服务器/客户端程序的新手。我刚刚学会了如何做停止等待,但我想尝试一下Go-Back-N。我制作了一个允许简单文件传输的程序,但我希望能够像我在Stop-and-Wait中那样从中获取更多信息:传输的数据包总数,发送的确认总数,收到的确认总数,收到的重复数据包总数,发送的数据总量和操作日志文件,记录客户端和服务器之间的所有活动。
我有一些更基本的统计数据,例如重传次数,传输时间和发送文件的通知,但这一次只适用于一个文件。我希望能够发送多个数据包。
到目前为止,这是我的代码:
接收器:
public class Receiver {
public static void main(String args[]) throws Exception {
System.out.println("Ready to receive the file!");
// Get the address, port and name of file to send over UDP
final int port = Integer.parseInt(args[0]);
final String fileName = args[1];
receiveAndCreate(port, fileName);
}
public static void receiveAndCreate(int port, String fileName) throws IOException {
// Create the socket, set the address and create the file to be sent
DatagramSocket socket = new DatagramSocket(port);
InetAddress address;
File file = new File(fileName);
FileOutputStream outToFile = new FileOutputStream(file);
// Create a flag to indicate the last message
boolean lastMessageFlag = false;
// Store sequence number
int sequenceNumber = 0;
int lastSequenceNumber = 0;
// For each message we will receive
while (!lastMessageFlag) {
// Create byte array for full message and another for file data without header
byte[] message = new byte[1024];
byte[] fileByteArray = new byte[1021];
// Receive packet and retreive message
DatagramPacket receivedPacket = new DatagramPacket(message, message.length);
socket.setSoTimeout(0);
socket.receive(receivedPacket);
message = receivedPacket.getData();
// Get port and address for sending ack
address = receivedPacket.getAddress();
port = receivedPacket.getPort();
// Retrieve sequence number
sequenceNumber = ((message[0] & 0xff) << 8) + (message[1] & 0xff);
// Retrieve the last message flag
if ((message[2] & 0xff) == 1) {
lastMessageFlag = true;
} else {
lastMessageFlag = false;
}
if (sequenceNumber == (lastSequenceNumber + 1)) {
// Update latest sequence number
lastSequenceNumber = sequenceNumber;
// Retrieve data from message
for (int i=3; i < 1024 ; i++) {
fileByteArray[i-3] = message[i];
}
// Write the message to the file
outToFile.write(fileByteArray);
System.out.println("Received: Sequence number = " + sequenceNumber +", Flag = " + lastMessageFlag);
// Send acknowledgement
sendAck(lastSequenceNumber, socket, address, port);
// Check for last message
if (lastMessageFlag) {
outToFile.close();
}
} else {
// If packet has been received, send ack for that packet again
if (sequenceNumber < (lastSequenceNumber + 1)) {
// Send acknowledgement for received packet
sendAck(sequenceNumber, socket, address, port);
} else {
// Resend acknowledgement for last packet received
sendAck(lastSequenceNumber, socket, address, port);
}
}
}
socket.close();
System.out.println("File " + fileName + " has been received.");
}
public static void sendAck(int lastSequenceNumber, DatagramSocket socket, InetAddress address, int port) throws IOException {
// Resend acknowledgement
byte[] ackPacket = new byte[2];
ackPacket[0] = (byte)(lastSequenceNumber >> 8);
ackPacket[1] = (byte)(lastSequenceNumber);
DatagramPacket acknowledgement = new DatagramPacket(ackPacket, ackPacket.length, address, port);
socket.send(acknowledgement);
System.out.println("Sent ack: Sequence Number = " + lastSequenceNumber);
}
}
发信人:
public class Sender {
public static void main(String args[]) throws Exception {
// Get the address, port and name of file to send over UDP
final String hostName = args[0];
final int port = Integer.parseInt(args[1]);
final String fileName = args[2];
createAndSend(hostName, port, fileName);
}
public static void createAndSend(String hostName, int port, String fileName) throws IOException {
System.out.println("Sending the file");
// Create the socket, set the address and create the file to be sent
DatagramSocket socket = new DatagramSocket();
InetAddress address = InetAddress.getByName(hostName);
File file = new File(fileName);
// Create a byte array to store the filestream
InputStream inFromFile = new FileInputStream(file);
byte[] fileByteArray = new byte[(int)file.length()];
inFromFile.read(fileByteArray);
// Start timer for calculating throughput
StartTime timer = new StartTime(0);
// Create a flag to indicate the last message and a 16-bit sequence number
int sequenceNumber = 0;
boolean lastMessageFlag = false;
// Create a flag to indicate the last acknowledged message and a 16-bit sequence number
int ackSequenceNumber = 0;
int lastAckedSequenceNumber = 0;
boolean lastAcknowledgedFlag = false;
// Create a counter to count number of retransmissions and initialize window size
int retransmissionCounter = 0;
int windowSize = 128;
// Vector to store the sent messages
Vector <byte[]> sentMessageList = new Vector <byte[]>();
// For as each message we will create
for (int i=0; i < fileByteArray.length; i = i+1021 ) {
// Increment sequence number
sequenceNumber += 1;
// Create new byte array for message
byte[] message = new byte[1024];
// Set the first and second bytes of the message to the sequence number
message[0] = (byte)(sequenceNumber >> 8);
message[1] = (byte)(sequenceNumber);
// Set flag to 1 if packet is last packet and store it in third byte of header
if ((i+1021) >= fileByteArray.length) {
lastMessageFlag = true;
message[2] = (byte)(1);
} else { // If not last message store flag as 0
lastMessageFlag = false;
message[2] = (byte)(0);
}
// Copy the bytes for the message to the message array
if (!lastMessageFlag) {
for (int j=0; j != 1021; j++) {
message[j+3] = fileByteArray[i+j];
}
}
else if (lastMessageFlag) { // If it is the last message
for (int j=0; j < (fileByteArray.length - i); j++) {
message[j+3] = fileByteArray[i+j];
}
}
// Package the message
DatagramPacket sendPacket = new DatagramPacket(message, message.length, address, port);
// Add the message to the sent message list
sentMessageList.add(message);
while (true) {
// If next sequence number is outside the window
if ((sequenceNumber - windowSize) > lastAckedSequenceNumber) {
boolean ackRecievedCorrect = false;
boolean ackPacketReceived = false;
while (!ackRecievedCorrect) {
// Check for an ack
byte[] ack = new byte[2];
DatagramPacket ackpack = new DatagramPacket(ack, ack.length);
try {
socket.setSoTimeout(50);
socket.receive(ackpack);
ackSequenceNumber = ((ack[0] & 0xff) << 8) + (ack[1] & 0xff);
ackPacketReceived = true;
} catch (SocketTimeoutException e) {
ackPacketReceived = false;
//System.out.println("Socket timed out while waiting for an acknowledgement");
//e.printStackTrace();
}
if (ackPacketReceived) {
if (ackSequenceNumber >= (lastAckedSequenceNumber + 1)) {
lastAckedSequenceNumber = ackSequenceNumber;
}
ackRecievedCorrect = true;
System.out.println("Ack recieved: Sequence Number = " + ackSequenceNumber);
break; // Break if there is an ack so the next packet can be sent
} else { // Resend the packet
System.out.println("Resending: Sequence Number = " + sequenceNumber);
// Resend the packet following the last acknowledged packet and all following that (cumulative acknowledgement)
for (int y=0; y != (sequenceNumber - lastAckedSequenceNumber); y++) {
byte[] resendMessage = new byte[1024];
resendMessage = sentMessageList.get(y + lastAckedSequenceNumber);
DatagramPacket resendPacket = new DatagramPacket(resendMessage, resendMessage.length, address, port);
socket.send(resendPacket);
retransmissionCounter += 1;
}
}
}
} else { // Else pipeline is not full, break so we can send the message
break;
}
}
// Send the message
socket.send(sendPacket);
System.out.println("Sent: Sequence number = " + sequenceNumber + ", Flag = " + lastMessageFlag);
// Check for acknowledgements
while (true) {
boolean ackPacketReceived = false;
byte[] ack = new byte[2];
DatagramPacket ackpack = new DatagramPacket(ack, ack.length);
try {
socket.setSoTimeout(10);
socket.receive(ackpack);
ackSequenceNumber = ((ack[0] & 0xff) << 8) + (ack[1] & 0xff);
ackPacketReceived = true;
} catch (SocketTimeoutException e) {
//System.out.println("Socket timed out waiting for an ack");
ackPacketReceived = false;
//e.printStackTrace();
break;
}
// Note any acknowledgements and move window forward
if (ackPacketReceived) {
if (ackSequenceNumber >= (lastAckedSequenceNumber + 1)) {
lastAckedSequenceNumber = ackSequenceNumber;
System.out.println("Ack recieved: Sequence number = " + ackSequenceNumber);
}
}
}
}
// Continue to check and resend until we receive final ack
while (!lastAcknowledgedFlag) {
boolean ackRecievedCorrect = false;
boolean ackPacketReceived = false;
while (!ackRecievedCorrect) {
// Check for an ack
byte[] ack = new byte[2];
DatagramPacket ackpack = new DatagramPacket(ack, ack.length);
try {
socket.setSoTimeout(50);
socket.receive(ackpack);
ackSequenceNumber = ((ack[0] & 0xff) << 8) + (ack[1] & 0xff);
ackPacketReceived = true;
} catch (SocketTimeoutException e) {
//System.out.println("Socket timed out waiting for an ack1");
ackPacketReceived = false;
//e.printStackTrace();
}
// If its the last packet
if (lastMessageFlag) {
lastAcknowledgedFlag = true;
break;
}
// Break if we receive acknowledgement so that we can send next packet
if (ackPacketReceived) {
System.out.println("Ack recieved: Sequence number = " + ackSequenceNumber);
if (ackSequenceNumber >= (lastAckedSequenceNumber + 1)) {
lastAckedSequenceNumber = ackSequenceNumber;
}
ackRecievedCorrect = true;
break; // Break if there is an ack so the next packet can be sent
} else { // Resend the packet
// Resend the packet following the last acknowledged packet and all following that (cumulative acknowledgement)
for (int j=0; j != (sequenceNumber-lastAckedSequenceNumber); j++) {
byte[] resendMessage = new byte[1024];
resendMessage = sentMessageList.get(j + lastAckedSequenceNumber);
DatagramPacket resendPacket = new DatagramPacket(resendMessage, resendMessage.length, address, port);
socket.send(resendPacket);
System.out.println("Resending: Sequence Number = " + lastAckedSequenceNumber);
// Increment retransmission counter
retransmissionCounter += 1;
}
}
}
}
socket.close();
System.out.println("File " + fileName + " has been sent");
// Calculate the average throughput
int fileSizeKB = (fileByteArray.length) / 1024;
int transferTime = timer.getTimeElapsed() / 1000;
double throughput = (double) fileSizeKB / transferTime;
System.out.println("File size: " + fileSizeKB + "KB, Transfer time: " + transferTime + " seconds. Throughput: " + throughput + "KBps");
System.out.println("Number of retransmissions: " + retransmissionCounter);
}
}
我想我的主要问题是将它从仅接受一个文件转换为多个文件?
提前谢谢!