0

I'm having trouble understanding why the receive call for a UDP connection does not seem to be blocking. Any help would be appreciated.

Basically, the full code is supposed to read and send byte segments of a file over via UDP to another running process listening at a specific port so that that process can then reconstruct (a copy) of the file. In this case however there is no such listener as of yet. The code below only includes the sections which I think the trouble is in.

import java.util.*;
import java.io.*;
import java.nio.*;
import java.net.*;

//... setup code ...

Datagram connection = null;
try {
    address = new InetSocketAddress(hostName, portNum); //Assume the hostName and portNum are valid (i.e. localhost, port 8250)
    connection = new DatagramSocket(address);
    connection.setSoTimeout(100); //This doesn't seem to work, even if I set this to 1000000
} catch (IOException e) {
    //Quit
    System.out.println(ERROR_UNABLE_TO_CONNECT);
    return;
}

//... read contents from sourceFile and create a DatagramPacket for sending first few bytes ...

boolean received = false;
byte[] ackPacketBuffer = new byte[1000];
DatagramPacket ackPacket = new DatagramPacket(ackPacketBuffer, ackPacketBuffer.length);
while(!received) { 
    try {
        connection.send(fileNamePacket); //fileNamePacket can be treated as the packet to be sent
        connection.receive(ackPacket); //From my understanding, this should block at least for the set time, before throwing SocketTimeoutException

        //... do some checks on the ackPacket, set received flag to be true if successful so that loop is broken...

    } catch (SocketTimeoutException e) {
        //Packet potentially lost, resend
        System.out.println(ERROR_TIMEOUT);
        continue;
    } catch (IOException e) {
        System.out.println(ERROR_SOCKET_WRITE);
        continue;
    }
}

From what I think should happen, given the scenario for which there is no listener for the specified port, the receive call should block, waiting for an acknowledgement which should never come, until the timeout value has expired, in which case a SocketTimeoutException should be thrown, activating the appropriate catch block and causing an error message to appear on the screen.

Unfortunately I get nothing - placing a print statement after the connection.receive() call shows an infinite loop. The infinite loop is to be expected, but why is it that I'm not getting a thrown SocketTimeoutException?

Other questions which I have encountered so far:

  1. setSotimeout on a datagram socket
  2. DatagramSocket not throwing SocketTimeout - Java
  3. Adding timeout to DatagramSocket - receive()
Community
  • 1
  • 1
Sean Tay
  • 23
  • 8
  • So you're receiving something. What? – user207421 Oct 10 '15 at 18:32
  • By right I should be receiving an ACK packet from the process listening at that port, which indicates it has successfully obtained the first packet. But since there is no such process at the moment, I think I should be at least getting the SocketTimeoutException. But the associated printout with the SocketTimeoutException never gets printed, which I don't get why. – Sean Tay Oct 11 '15 at 01:05
  • The fact is clearly that you *are* receiving *something.* I say again. What? Trace the packet that is received. You might get a surprise. – user207421 Oct 11 '15 at 09:10
  • Apologies for the late response. I checked the contents of the packet "received", but it was an empty packet. No matter though, I have already resolved the issue. Thank you for your time though :) – Sean Tay Oct 12 '15 at 05:10
  • Cannot reproduce. The code doesn't even compile, and if as you allege the `hostName` is, incorrectly, the target hostname I get a `BindException` when constructing the `DatagramSocket.` If `hostName` is local I get `SocketTimeoutException.` Clearly this is not the real code, and clearly you have ignored one or more exceptions in the real code. – user207421 Nov 19 '15 at 03:28

1 Answers1

1

I have resolved the issue. Previously the DatagramSocket had the InetSocketAddress. Now, instead of passing in the InetSocketAddress to the DatagramSocket constructor, I do not pass in anything:

connection = new DatagramSocket();

The DatagramPackets sent through the DatagramSocket will be the one that has the InetSocketAddress instead.

Sean Tay
  • 23
  • 8
  • It causes the `DatagramSocket` to be bound to that IP address, and so to only receive packets that are addressed to exactly that IP address (modulo the weak-end system model, if that applies). If you don't supply it, or supply `null`, it binds to 0.0.0.0, which means 'receive from any local IP address'. – user207421 Oct 12 '15 at 05:44
  • And note that your question specifically says 'Assume the hostName and portNum are valid'. They weren't. – user207421 Oct 12 '15 at 05:52
  • The hostName and portNum (in the InetSocketAddress object) works when submitted to the DatagramPacket, it doesn't work when submitted to the DatagramSocket. – Sean Tay Oct 13 '15 at 14:24
  • Ah I see, I should have made it clearer. The hostName and portNum in this case is the InetAddress to send the data to. So in this case the DatagramSocket's constructor takes in the InetSocketAddress to listen at, and not the InetSocketAddress to send to? – Sean Tay Oct 13 '15 at 14:30
  • You can only bind a socket to a local IP address. NB using the word 'connect' in your error message `ERROR_UNABLE_TO_CONNECT` is just misleading. The error would occur if and only if you were unable to *create* or *bind* the socket or lookup the target address or set the read timeout. – user207421 Nov 19 '15 at 03:18