Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to achieve timeout handling in blocking DatagramChannel without using selectors

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

like image 391
Fredrik Israelsson Avatar asked Mar 11 '13 11:03

Fredrik Israelsson


2 Answers

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.

like image 132
D-Dᴙum Avatar answered Oct 23 '22 16:10

D-Dᴙum


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();
like image 1
user1537366 Avatar answered Oct 23 '22 16:10

user1537366