servidor - udp socket server example java
¿Es posible usar solo 1 UDPSocket para enviar/recibir en el mismo puerto? (2)
¿Cómo el servidor puede enviar al cliente usando su propio puerto? Está enviando ACK de servidor a cliente en el puerto del Servidor, debe obtener el puerto UDP del cliente del paquete recibido y enviar datos a ese puerto.
EDITAR
Cambiar en el servidor en el método SendACK a:
ackPacket = new DatagramPacket(ackArray, ackArray.length, InetAddress.getByName("localhost"), incomingPacket.getPort());
Y ahora analiza el código ejecutando.
Estoy tratando de enviar un DatagramPacket, y luego debo esperar un Reconocimiento de servidor, para saber si tengo que volver a enviar el mismo paquete o enviar el siguiente.
Estoy usando para eso el mismo socket en el cliente, para enviar el paquete de datos y para recibir el reconocimiento (ack), y lo mismo en el lado del servidor, otro socket que se utiliza para recibir el paquete de datos y luego enviar el acuse de recibo al cliente..
El primer problema es que el cliente está enviando el paquete de datos, el servidor lo está recibiendo y luego envía el acuse de recibo al cliente, pero el cliente bloquea al recibir el paquete de acuse de recibo.
Estoy creando System.out.println para identificar dónde está el problema, pero no pude encontrar ninguna solución a este problema.
El segundo problema es que el Servidor todavía está recibiendo datos, y no espere a que el cliente envíe algo, lo compré porque obtuve esas líneas (como "tengo paquete con longitud xxx" "ack enviado con ackNr yyy" ... "impreso por el lado del servidor, todo el tiempo aunque el cliente está bloqueando después de enviar el primer paquete, ¡porque está esperando el reconocimiento que no se recibió!
Aquí está el código del CLIENTE:
package blatt7;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.util.zip.CRC32;
public class FileSender {
String zielRechner;
String filePath;
InetAddress host;
File file;
FileInputStream fis;
int readLength;
int sequenceNr = 0;
int receivedSeqNr = 1;
static int port = 7777;
int packetNr = 0;
byte[] packet = new byte[1216];
byte[] data = new byte[1200];
byte[] header = new byte[16];
byte[] readLengthByte = new byte[4];
byte[] sequenceNrByte = new byte[4];
byte[] checksumByte = new byte[8];
byte[] ackBuffer = new byte[4];
CRC32 checksumCalculator = new CRC32();
DatagramPacket dp;
DatagramPacket ackPacket;
DatagramSocket sendSocket = null;
//DatagramSocket ackSocket = null;
static boolean ackReceived = true;
public FileSender(String zielRechner, String filePath) throws UnknownHostException, FileNotFoundException {
this.zielRechner = zielRechner;
this.filePath = filePath;
this.host = InetAddress.getByName(zielRechner);
this.file = new File(filePath);
fis = new FileInputStream(file);
}
public void sendFile() throws IOException {
while((readLength = fis.read(data)) != -1) {
if (sequenceNr == 1)
sequenceNr = 0;
else
sequenceNr = 1;
readLengthByte = intToBytes(readLength);
sequenceNrByte = intToBytes(sequenceNr);
for(int i=0; i<4; i++) {
header[8+i] = readLengthByte[i];
}
for(int i=0; i<4; i++) {
header[12+i] =sequenceNrByte[i];
}
int j=0;
for (int i=0; i<packet.length; i++) {
if (i < header.length)
packet[i] = header[i];
else {
packet[i] = data[j];
j++;
}
}
checksumCalculator.reset();
checksumCalculator.update(packet,8,8+readLength);
checksumByte = longToBytes(checksumCalculator.getValue());
for(int i=0; i < 8; i++) {
packet[i] = checksumByte[i];
}
dp = new DatagramPacket(packet, packet.length, host, port);
while(receivedSeqNr == sequenceNr && ackReceived) {
try {
ackReceived = false;
sendSocket = new DatagramSocket();
sendSocket.send(dp);
sendSocket.setSoTimeout(10000);
packetNr++;
System.out.println("Packet sent with seqNr: " + sequenceNr + " and length: " + bytesToInt(readLengthByte, 0) + " - PACKET NR: " + packetNr);
ackPacket = new DatagramPacket(ackBuffer, ackBuffer.length);
System.out.println("TEST!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
sendSocket.receive(ackPacket);
System.out.println("Receiving ACK!!");
ackReceived = true;
ackBuffer = ackPacket.getData();
receivedSeqNr = bytesToInt(ackBuffer,0);
System.out.println("got SequenceNr with receivedSeq-Nr: " + receivedSeqNr);
} catch (SocketTimeoutException e) {
e.printStackTrace();
break;
}
}
}
fis.close();
System.out.println("Transfer Completed Successfully!");
sendSocket.close();
}
public static byte[] longToBytes(long value) {
ByteBuffer buffer = ByteBuffer.allocate(8);
buffer.putLong(value);
return buffer.array();
}
public static long bytesToLong(byte[] bytes, int index) {
ByteBuffer buffer = ByteBuffer.allocate(8);
buffer.put(bytes);
buffer.flip();//need flip
return buffer.getLong(index);
}
public static byte[] intToBytes(int value) {
ByteBuffer buffer = ByteBuffer.allocate(4);
buffer.putInt(value);
return buffer.array();
}
public static int bytesToInt(byte[] bytes, int index) {
ByteBuffer buffer = ByteBuffer.allocate(4);
buffer.put(bytes);
buffer.flip();//need flip
return buffer.getInt(index);
}
public static void main(String[] args) throws IOException,ClassNotFoundException {
FileSender sender = new FileSender("localhost", "C:/Users/Kb/Desktop/Deepophile - Psychedelic Sessions.wav");
sender.sendFile();
}
}
y aquí está el código del SERVIDOR:
package blatt7;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.zip.CRC32;
public class FileReceiver {
byte[] incomingBuffer;
DatagramPacket incomingPacket;
DatagramSocket receiveSocket;
DatagramPacket ackPacket;
int packetCounter = 0;
int dataLength;
int receivedSeqNr;
long calculatedChecksum;
long receivedChecksum;
CRC32 checksumCalculator = new CRC32();
byte[] dataLengthByte = new byte[4];
byte[] receivedSeqNrByte = new byte[4];
byte[] receivedChecksumByte = new byte[8];
byte[] ackArray;
public FileReceiver() throws SocketException {
incomingBuffer = new byte[1500];
incomingPacket = new DatagramPacket(incomingBuffer, incomingBuffer.length);
}
public void receive() throws IOException {
receiveSocket = new DatagramSocket(FileSender.port);
receiveSocket.setSoTimeout(10000);
System.out.println("Server socket created. Waiting for incoming data...");
while(true && FileSender.ackReceived)
{
receiveSocket.receive(incomingPacket);
packetCounter++;
for (int i=0; i <4; i++) {
dataLengthByte[i] = incomingBuffer[8+i];
}
dataLength = FileSender.bytesToInt(dataLengthByte,0);
checksumCalculator.reset();
checksumCalculator.update(incomingBuffer, 8, dataLength+8);
calculatedChecksum = checksumCalculator.getValue();
for (int i=0; i <4; i++) {
receivedSeqNrByte[i] = incomingBuffer[12+i];
}
receivedSeqNr = FileSender.bytesToInt(receivedSeqNrByte,0);
for (int i=0; i <8; i++) {
receivedChecksumByte[i] = incomingBuffer[i];
}
long receivedChecksum = FileSender.bytesToLong(receivedChecksumByte,0);
System.out.println("Got packet with checksum: " + receivedChecksum);
System.out.println("Server-calculated checksum: " + calculatedChecksum);
System.out.println("Got packet with seqNr: " + receivedSeqNr + " and length: " + dataLength);
if (calculatedChecksum != receivedChecksum) {
sendACK(receivedSeqNr);
System.out.println("Packet have erros(s)! It must be sent another time!");
}
else if(calculatedChecksum == receivedChecksum && receivedSeqNr == 1) {
sendACK(0);
System.out.println("SeqNr ''0'' sent");
}
else if (calculatedChecksum == receivedChecksum && receivedSeqNr == 0) {
sendACK(1);
System.out.println("SeqNr ''1'' sent");
}
}
}
public void sendACK(int seqNum) throws IOException {
byte[] ackArray = FileSender.intToBytes(seqNum);
ackPacket = new DatagramPacket(ackArray, ackArray.length, InetAddress.getByName("localhost"), FileSender.port);
receiveSocket.send(ackPacket);
}
public static void main(String[] args) throws IOException,ClassNotFoundException {
FileReceiver receiver = new FileReceiver();
receiver.receive();
}
}
Puedes intentar ejecutarlo para ver dónde está el problema ... Así que POR FAVOR, si tienes CUALQUIER idea de cómo puedo resolver este problema, ¡házmelo saber!
¡Muchas gracias!
¿Alguien puede decirme dónde encontrar el archivo recibido? o ¿cómo debería cambiar mi código para que elija dónde guardarlo?
Sí, es posible. Su problema es que tiene la dirección de destino: puerto incorrecto al enviar el datagrama de ACK. Debería obtener la dirección de destino: puerto del DatagramPacket recibido, o simplemente reutilizar ese datagrama con datos diferentes como el datagrama de ACK.