I am using NIO and ServerSocketChannel. After I create a connection, I can’t wait more than 10 seconds between each input from the client. Otherwise I want to timeout the connection. This is while handling hundreds of connections at once. What’s the best way to do this? What would be really cool is if my selector could return a key when a connection doesn’t send me anything after 10 seconds. I could also selector.select(1) and just test every 1 second but that seems like overkill. Right now I have another Thread dealing with timeouts. What’s the best way to do this?
I wouldn’t use that, I dont think it does quite what you think it does (and it can be a bit odd on different platforms - but maybe that’s not something OP is worried about, shrug)
Assuming OP can’t just drop the connection “the next time it does something AFTER the ten seconds is up” (easiest way, normally most efficient too), I would:
each time you get a selectable key, set a timestamp in a map saying that you just received something at this time, with that key as the key
separate thread iterates over that map periodically finding victims, and uses the selectable key objects to remove them from the selector and drop the channel
that sounds like a good way to do it, but why in separate thread? You could check when last communication was done at the end of same (selector) thread, that is if you don’t think it would slow every select noticably. I think it wouldn’t.
The javadoc says “With this option set to a non-zero timeout, a read() call on the InputStream associated with this Socket will block for only this amount of time” Because I’m using non blocking sockets and this function was written in 1.1, I’m not sure it will do what I want. I don’t want to just ‘drop’ the connection though. I want to know when it was dropped so I can log it and clean up stuff.
I’m afraid of some hax0r just making connections and letting them sit for an easy DoS. On a non-hax0r note I want to notify the other plays that their opponent has timed out as soon as possible.
I’m currently doing something very similar. I have a DelayQueue running in another Thread.
If you block on select, how do you cleanly shutdown your application? I wanted to make my design so that I could shutdown my server socket thread without having to System.exit(), so I have a shutdown boolean that I can set and loop like this:
while (!shutdownActivated){
if (selector.select(500)!=0){
}
}
I was thinking this lets me not spend to much in busy loop, while at the same time letting me cleanly shut down the thread without a system exit. Do you know of a way to have my selector select a special key when I want to shutdown the application?
my appologies, cap21 mentioned it in his first pos, when scrooling breafly to see who posted I’ve looked wrong I guess. … so much trash replys over nothing, moderator can erase those…
(you should be able to test that very easily with a second machien on your LAN!)
The overhead for additional open channels using NIO is sufficiently small that you shouldnt get significant problems beyond your OS problem of running out of sockets.
Even that probably isn’t going to happen until long after your server crashes because of lack of open file handles
And how hard is it for someone just to open the connections and then send junk every 1 second? Have you handled that fully?
(not trying to put you off doing it, just pointing out it’s quite a long road to go down once you start worrying about that)
I’m currently doing something very similar. I have a DelayQueue running in another Thread.
To be clear, setSoTimeout does or does not work for NIO? Everything in the doc says it is for blocking opperations. Here is my test code that doesn’t seem to do anything:
while (true){
if (selector.select()!=0){
System.out.println("Selector returned.");
Set keys=selector.selectedKeys();
Iterator i=keys.iterator();
while (i.hasNext()){
SelectionKey key=(SelectionKey) i.next();
i.remove();
if (key.isAcceptable()){
System.out.println("Got new one.");
ServerSocketChannel ss2=(ServerSocketChannel) key.channel();
SocketChannel newCon=ss2.accept();
newCon.configureBlocking(false);
newCon.register(key.selector(),SelectionKey.OP_READ);
newCon.socket().setSoTimeout(200); //***HERE IS MY TIMEOUT***
}
if (key.isReadable()){
ByteBuffer buf = ByteBuffer.allocateDirect(1024);
int numBytesRead = ((SocketChannel)key.channel()).read(buf);
if (numBytesRead==-1) {
key.channel().close();
continue;
}
buf.flip();
Charset myCharset = Charset.forName( "ISO-8859-1" );
System.out.println("Is readable:"+myCharset.decode(buf).toString());
}
}
}
}