Setting timeout on blocking I/O ops with ServerSocketChannel doesn't work as expected

StackOverflow https://stackoverflow.com/questions/17133620

  •  31-05-2022
  •  | 
  •  

I'm working on a small group conversation server in Java and I'm currently hacking network code, but it seems like I cannot set right timeout on blocking I/O ops: chances are I've been bitten by some Java weirdness (or, simply, I misinterpret javadoc).

So, this is the pertinent code from ConversationServer class (with all security checks and logging stripped for simplicity):

class ConversationServer {

    // ...

    public int setup() throws IOException {
        ServerSocketChannel server = ServerSocketChannel.open();
        server.bind(new InetSocketAddress(port), Settings.MAX_NUMBER_OF_PLAYERS + 1);

        server.socket().setSoTimeout((int) Settings.AWAIT_PLAYERS_MS);

        int numberOfPlayers;

        for (numberOfPlayers = 0; numberOfPlayers < Settings.MAX_NUMBER_OF_PLAYERS; ++numberOfPlayers) {
            SocketChannel clientSocket;

            try {
                clientSocket = server.accept();
            } catch (SocketTimeoutException timeout) {
                break;
            }

            clients.add(messageStreamFactory.create(clientSocket));
        }

        return numberOfPlayers;
    }

    // ...

}

The expected behaviour is to let connect Settings.MAX_NUMBER_OF_PLAYERS clients at most, or terminate setup anyway after Settings.AWAIT_PLAYER_MS milliseconds (currently, 30000L).

What happens, is that if I connect Settings.MAX_NUMBER_OF_PLAYERS clients, everything is fine (exit because of for condition), but if I don't, the SocketTimeoutException I'd expect is never thrown and the server hangs forever.

If I understand right, server.socket().setSoTimeout((int) Settings.AWAIT_PLAYERS_MS); should be sufficient, but it doesn't give the expected behaviour.

So, can anyone spot the error here?

有帮助吗?

解决方案

It looks like the timeout works if you change from

server.socket().setSoTimeout((int) Settings.AWAIT_PLAYERS_MS);
server.accept();

to

server.socket().setSoTimeout((int) Settings.AWAIT_PLAYERS_MS);
server.socket().accept();

I.e. call accept() on the same object on which you set the SO timeout. I don't know enough about NIO sockets to say exactly what results from doing this. Maybe somebody else can shed some light.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top