如何在不使用选择器的情况下在阻塞 DatagramChannel 中实现超时处理

9
我感觉我可能错过了一些非常显然的东西。
我的系统整体结构让我想使用阻塞DatagramChannel而不使用Selectors,以保持简单。我尝试通过在套接字上设置超时来实现超时处理,但这似乎没有效果。
下面是伪代码,给出了我想要实现的内容。
DatagramChannel channel = DatagramChannel.open(); channel.socket().bind(某个地址); channel.socket().setSoTimeout(3000); channel.send(outBuffer, 对等地址);
channel.receive(inBuffer);
另一方面,我有一个UDP服务器,它会快速地返回五个响应,然后为了测试目的,在发送第六个响应之前延迟约五秒钟。
这个延迟不会触发SocketTimeoutException。为什么?调用channel.receive时好像没有考虑套接字上设置的超时。
谢谢, Fredrik

我最近发现setSoTimeout()对SocketChannel读取不起作用,而且看起来对DatagramChannels也不起作用。为什么,我无法想象。难道你不能使用DatagramSocket吗? - user207421
没有什么特别的原因,只是觉得DatagramChannel看起来更好看。 - Fredrik Israelsson
它确实有这个奇怪的空白,但是。 - user207421
1
您应该考虑接受给出的答案。 - D-Dᴙum
2个回答

7

显然,DatagramChannel无法超时的问题并不是一个错误,而是:

不是一个错误。SocketChannel(和DatagramChannel)中的读取方法不支持超时。如果需要超时功能,则使用相关Socket(或DatagramSocket)对象的读取方法。

链接。


谢谢。我觉得这完全是离奇的。 - user207421
1
我必须在这方面同意您的看法。我自己也正在学习SocketChannels,那么我们应该使用Selector吗? - D-Dᴙum
1
显然,但这也迫使您使用非阻塞模式。这仍然很奇怪。没有理由不支持读取超时。在C层面上,套接字就是套接字。 - user207421
这很奇怪,因为 DatagramChannel 文档说:Datagram 通道支持读操作的超时。如果 datagram 通道处于阻塞模式,并且通过调用其套接字的 setSoTimeout 方法设置了超时时间,则如果在超时期满之前调用接收或读取方法但未能完成,则会抛出 TimeoutException。 - Bram

1
这是我做的:

创建一个Interrupter

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){}
        }
    }
}

设置中断器

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

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接