I am trying to add a write timeout to a SocketChannel by using a Selector:
public int write(ByteBuffer buf, long timeout, SocketChannel socketChannel, Selector selector) {
int written = socketChannel.write(buf);
if (written == 0) {
SelectionKey selectionKey = socketChannel.register(selector, SelectionKey.OP_WRITE);
try {
selector.select(timeout);
if (Thread.interrupted()) {
throw new InterruptedIOException();
}
written = socketChannel.write(buf);
} finally {
selectionKey.cancel();
}
}
return written;
}
The plan is to reuse the selector and de-register it after each timeout. But apparently I get the same selectionKey that was previously cancelled if I call my method twice and it is unable to write at all. This results in a CancelledKeyException when register is called during the second method call. I thought I would get a new selectionKey after the first was cancelled.
So how do I do this? I guess calling selectNow() before the register or after the cancel, in order to clear the cancelled keys will solve it but it seems weird, is there a better way?