Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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??

like image 331
ZelelB Avatar asked Dec 29 '12 20:12

ZelelB


2 Answers

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.

like image 130
user207421 Avatar answered Sep 21 '22 05:09

user207421


How server can send to client using own port? You are sending ACK from server to client on Server's port, you should get client's UDP port from received packet and send data to that port.

EDIT

Change in Server in SendACK method to:

ackPacket = new DatagramPacket(ackArray, ackArray.length, InetAddress.getByName("localhost"), incomingPacket.getPort());

And now analyze code by running.

like image 23
nullptr Avatar answered Sep 19 '22 05:09

nullptr