Is it possible to use just 1 UDPSocket for sending/receiving on the same port?

ZelelB picture ZelelB · Dec 29, 2012 · Viewed 7.2k times · Source

I'm trying to send a DatagramPacket, and then must wait for an Acknowlegment from sever, so that I know if I have to resend the same packet or send the next one..

I'm using for that the same socket on the client, to send the datapacket and to receive the acknowlegment (ack), and same in the server's side, another socket that is used to receive the datapacket and then to send the acknowledgment to the client..

The 1st problem is that the client is sending the datapacket, the server is receiving it, then sends the acknowledgment to client, but the client blocks on receiving the Acknowledgment-packet.

I'm making some System.out.println to identify where is the problem, but I couldnt find any solution to this problem.

The 2nd problem is that the Server is still always receiving data, and dont wait for the client to send something, i checked that because i got that lines(like "got packet with length xxx" "ack sent with ackNr yyy" ..." printed on the server's side, all the time although the client is blocking after sending the 1st packet, because it's waiting for the acknowledgment that is not received!

Here is the CLIENT's code:

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();

}

}

and here is the SERVER's code:

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();     
}

}

You can try to execute it to see where the problem is... So PLEASE if you have ANY idea how can I solve this problem, let me know!

Thankyou verymuch!

Can anyone tell me where to find the received file? or how should I change my code so that I choose where to save it??

Answer

user207421 picture user207421 · Dec 30, 2012

Yes it is possible. Your problem is that you have the target address:port wrong when sending the ACK datagram. You should get the target address:port from the received DatagramPacket, or simpler still just reuse that datagram with different data as the ACK datagram.