Java 制作跟踪更多统计信息的UDP服务器/客户端程序
我不熟悉编写服务器/客户端程序。我刚刚学会了如何停止等待,但我想尝试一下返回N。我制作了一个程序,允许简单的文件传输,但我希望能够从中获得更多信息,就像我在停止等待中所做的那样:传输的数据包总数,发送的确认总数,接收到的确认总数、接收到的重复数据包总数、发送的数据总量和操作日志文件,记录客户端和服务器之间的所有活动 我有一些更基本的统计数据,比如重新传输的次数、传输时间和发送文件的通知,但一次只能处理一个文件。我希望能够发送多个数据包 以下是我目前的代码: 接收人:Java 制作跟踪更多统计信息的UDP服务器/客户端程序,java,udp,client-server,sliding-window,Java,Udp,Client Server,Sliding Window,我不熟悉编写服务器/客户端程序。我刚刚学会了如何停止等待,但我想尝试一下返回N。我制作了一个程序,允许简单的文件传输,但我希望能够从中获得更多信息,就像我在停止等待中所做的那样:传输的数据包总数,发送的确认总数,接收到的确认总数、接收到的重复数据包总数、发送的数据总量和操作日志文件,记录客户端和服务器之间的所有活动 我有一些更基本的统计数据,比如重新传输的次数、传输时间和发送文件的通知,但一次只能处理一个文件。我希望能够发送多个数据包 以下是我目前的代码: 接收人: public class R
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);
}
}
公共类接收器{
公共静态void main(字符串args[])引发异常{
System.out.println(“准备接收文件!”);
//获取要通过UDP发送的文件的地址、端口和名称
final int port=Integer.parseInt(args[0]);
最终字符串文件名=args[1];
接收和创建(端口、文件名);
}
公共静态void receiveAndCreate(int端口,字符串文件名)引发IOException{
//创建套接字,设置地址并创建要发送的文件
DatagramSocket套接字=新DatagramSocket(端口);
地址;
文件=新文件(文件名);
FileOutputStream outToFile=新的FileOutputStream(文件);
//创建标志以指示最后一条消息
布尔lastMessageFlag=false;
//存储序列号
int sequenceNumber=0;
int lastSequenceNumber=0;
//对于我们将收到的每条消息
while(!lastMessageFlag){
//为完整消息创建字节数组,为不带头的文件数据创建另一个字节数组
字节[]消息=新字节[1024];
字节[]fileByteArray=新字节[1021];
//接收数据包并检索消息
DatagramPacket receivedPacket=新的DatagramPacket(message,message.length);
插座。设置插座输出(0);
插座。接收(接收分组);
message=receivedPacket.getData();
//获取用于发送ack的端口和地址
地址=receivedPacket.getAddress();
port=receivedPacket.getPort();
//检索序列号
sequenceNumber=((消息[0]&0xff)>8);
ackPacket[1]=(字节)(lastSequenceNumber);
DatagramPacket确认=新的DatagramPacket(ackPacket,ackPacket.length,address,port);
socket.send(确认);
System.out.println(“发送确认:序列号=“+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);
}
}
公共类发送方{
公共静态void main(字符串args[])引发异常{
//获取要通过UDP发送的文件的地址、端口和名称
最终字符串hostName=args[0];
final int port=Integer.parseInt(args[1]);
最终字符串文件名=args[2];
createAndSend(主机名、端口、文件名);
}
公共静态void createAndSend(字符串主机名、int端口、字符串文件名)引发IOException{
System.out.println(“发送文件”);
//创建套接字,设置地址并创建要发送的文件
DatagramSocket套接字=新DatagramSocket();
InetAddress=InetAddress.getByName(主机名);
文件=新文件(文件名);
//创建一个字节数组来存储文件流
InputStream INFOROMFILE=新文件InputStream(文件);
byte[]fileByteArray=新字节[(int)file.length()];
read(fileByteArray);
//用于计算吞吐量的启动计时器
开始时间计时器=新的开始时间(0);
//创建一个标志以指示最后一条消息和一个16位序列号
int sequenceNumber=0;
布尔lastMessageFlag=false;
//创建一个标志以指示最后确认的消息和一个16位序列号
int ackSequenceNumber=0;
int lastAckedSequenceNumber=0;
布尔lastAcknowledgedFlag=false;
//创建计数器以计算重新传输的次数并初始化窗口大小
int重新传输计数器=0;
int windowSize=128;
//向量来存储发送的消息
Vector sentMessageList=新向量();
//因为我们将创建每一条消息
for(int i=0;i>8);
消息[1]=(字节)(序列号);
//若数据包是最后一个数据包,则将标志设置为1,并将其存储在报头的第三个字节中
如果((i+1021)>=fileByteArray.length){
lastMessageFlag=true;
消息[2]=(字节)(1);
}else{//如果不是,则最后一个消息存储标志为0
lastMessageFlag=false;
消息[2]=(字节)(0);
}
//将消息的字节复制到消息数组
如果(!lastMessageFlag){
对于(int j=0;j!=1021;j++){
消息[j+3]=fileByteArray[i+j];
}
}
else if(lastMessageFlag){//如果它是最后一条消息
对于(int j=0;j<(fileByteArray.length-i);j++){
消息[j+3]=fileByteArray[i+j];
}
}
//打包消息
DatagramPacket sendPacket=新的DatagramPacket(message,message.length,address,port);
//将邮件添加到已发送邮件列表中
sentMessageList.add(消息);
while(true){
//如果下一步