How to achieve timeout handling in blocking DatagramChannel without using selectors
Asked Answered
A

2

9

I get a feeling that I am missing something really obvious here.

The overall structure of my system makes me want to use a blocking DatagramChannel without Selectors, in order to keep things simple. I am trying to achieve timeout handling by setting a timeout on the socket, but this seems to have no effect.

This pseudoized code gives a hint of what I am trying to achieve.

DatagramChannel channel = DatagramChannel.open();
channel.socket().bind(some address);
channel.socket().setSoTimeout(3000);
channel.send(outBuffer, peerAddress);

channel.receive(inBuffer);

On the other side, I have a UDP server that gives five quick responses, and then, for testing purposes, delays about five seconds before delivering the sixth response.

The delay does not trigger a SocketTimeoutException. Why is that? The timeout set on the socket does not seem to be taken into consideration when calling channel.receive.

Regards, Fredrik

Affectation answered 11/3, 2013 at 11:49 Comment(4)
I've recently discovered that setSoTimeout() doesn't work for SocketChannel reads, and it looks like it doesn't work for DatagramChannels either. Why, I cannot imagine. Is there some reason you can't use a DatagramSocket?Bohun
No reason. Just thought DatagramChannel looks nicer.Affectation
It does, but it has this strange lacuna.Bohun
You should consider accepting one of the given answers.Lachman
L
7

Apparently the issue of not being able to timeout is not a bug with DatagramChannel, but that:

Not a bug. The read methods in SocketChannel (and DatagramChannel) do not support timeouts. If you need the timeout functionality then use the read methods of the associated Socket (or DatagramSocket) object.

Link.

Lobeline answered 14/10, 2013 at 21:8 Comment(3)
I have to agree with you there. I'm just learning SocketChannels myself so are we supposed to use a Selector instead?Lachman
Apparently, but that also forces you to use non-blocking mode. It remains bizarre. There is no reason for read timeouts not to be supported. A socket is a socket at the C layer.Bohun
This is quite strange, as the DatagramChannel doc says: Datagram channels support timeouts on read operations. If a datagram channel is in blocking mode, and a timeout period has been set by invoking its socket's setSoTimeout method, then a TimeoutException is thrown if a receive or read method is invoked but fails to complete before the timeout period expires.Aimless
G
1

This is what I did:

Create an Interrupter class

static private class Interrupter implements Runnable
{
    private final Thread th1;
    private volatile int wait=-1;
    private Interrupter(Thread ith1)
    {
        th1=ith1;
    }
    public void run()
    {
        while(true)
        {
            try{
                if( wait<0 ){ th1.join(); break; }
                else{ Thread.sleep(wait); th1.interrupt(); wait=-1; }
            } catch(Exception e){}
        }
    }
}

Setup the Interrupter

Interrupter ir1=new Interrupter(Thread.currentThread());
Thread th1=new Thread(ir1);
th1.start();
// We need this so that later the wait variable
// can be passed in successfully
while( th1.getState()!=Thread.State.WAITING );

Use the Interrupter

try{
    ir1.wait=waitTimeout;
    th1.interrupt();
    // Receive on the socket
    dc2.receive(bb2);
} catch(ClosedByInterruptException e){
    // (Timed out)
    Thread.interrupted();
    dc2.close();
    // Handle timeout here
    // ...
    // We need this so that later the wait variable
    // can be passed in successfully
    while( th1.getState()!=Thread.State.WAITING );
}
// Received packet
ir1.wait=-1;
th1.interrupt();
// We need this so that later the wait variable
// can be passed in successfully
while( th1.getState()!=Thread.State.WAITING );
Thread.interrupted();
Grasso answered 28/12, 2013 at 12:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.