Java NIO selector.select() always returns only one SelectionKey for OP_ACCEPT SelectionKey

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

  •  05-07-2023
  •  | 
  •  

I have written a java NIO server using selector to accept connections from clients.

I thought a selector.select() will block and return multiple keys. I just registered the selector for OP_ACCEPT and it always returns 1 key at a time

Am I doing something wrong?

package com.bay.srikanth.client;

import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

public class FloodServer {

    private final static Logger LOGGER = Logger.getLogger(FloodServer.class.getName());

    private static int PORT = 5555;
    private static ConcurrentHashMap<Integer, SocketChannel> chm
                        = new ConcurrentHashMap<Integer, SocketChannel>();
    private static int msg = 0;
    public static void main(String args[]) throws Exception {
        // Create a new selector
        Selector selector = Selector.open();
        // Open a listener on each port, and register each one
        ServerSocketChannel ssc = ServerSocketChannel.open();
        ssc.configureBlocking(false);
        ServerSocket ss = ssc.socket();            
        InetSocketAddress address = new InetSocketAddress(PORT);
        ss.bind(address);
        //registers ACCEPT
        ssc.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("Going to listen on " + PORT);

        while (true) {
            LOGGER.log(Level.INFO, "Total active connections : " + chm.size());
            selector.select();
            Set<SelectionKey> selectedKeys = selector.selectedKeys();
            LOGGER.log(Level.INFO, "Selected Keys on : " + selectedKeys + " with keys count : " + selectedKeys.size());
            Iterator<SelectionKey> it = selectedKeys.iterator();            

            while (it.hasNext()) {
                SelectionKey key = (SelectionKey) it.next();
                if ((key.readyOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT) {
                    // Accept the new connection
                    ServerSocketChannel sscNew = (ServerSocketChannel) key.channel();
                    SocketChannel sc = sscNew.accept();
                    sc.configureBlocking(false);
                    // Add the new connection to the selector                    
                    //sc.register(selector, SelectionKey.OP_READ);
                    // Add the socket channel to the list
                    chm.put(sc.hashCode(), sc);
                    it.remove();
                }
            }
        }        
    }        
}

Flood Test client tool

package com.bay.srikanth.client;

import java.net.InetSocketAddress;
import java.nio.channels.SocketChannel;
import java.util.List;
import java.util.Vector;

public class FloodTest implements Runnable {

private static List<SocketChannel> channelSet = new Vector<SocketChannel>();

@Override
public void run() {
    try {
        for(int i=0; i<50; i++) {
            SocketChannel socketChannel = SocketChannel.open();
            socketChannel.configureBlocking(true);
            //socketChannel.connect(new InetSocketAddress("10.9.242.70", 5555));
            socketChannel.connect(new InetSocketAddress("localhost", 5555));
            channelSet.add(socketChannel);
        } 
    } catch(Exception ex) {
        System.out.println(ex);
    }
    System.out.println(channelSet.size());
    try {
        Thread.sleep(30000);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

public static void main(String args[]) throws InterruptedException {
    for(int i=0; i<100; i++) {
        new Thread(new FloodTest()).start();
    }
}

}

Response log on server: (Partial)

Apr 17, 2014 11:35:49 AM com.bay.srikanth.client.FloodServer main
INFO: Selected Keys on : [sun.nio.ch.SelectionKeyImpl@5e176f] with keys count : 1
Apr 17, 2014 11:35:49 AM com.bay.srikanth.client.FloodServer main
INFO: Total active connections : 2328
Apr 17, 2014 11:35:49 AM com.bay.srikanth.client.FloodServer main
INFO: Selected Keys on : [sun.nio.ch.SelectionKeyImpl@5e176f] with keys count : 1
Apr 17, 2014 11:35:49 AM com.bay.srikanth.client.FloodServer main
INFO: Total active connections : 2329
Apr 17, 2014 11:35:49 AM com.bay.srikanth.client.FloodServer main
INFO: Selected Keys on : [sun.nio.ch.SelectionKeyImpl@5e176f] with keys count : 1
Apr 17, 2014 11:35:49 AM com.bay.srikanth.client.FloodServer main
INFO: Total active connections : 2330
Apr 17, 2014 11:35:49 AM com.bay.srikanth.client.FloodServer main
INFO: Selected Keys on : [sun.nio.ch.SelectionKeyImpl@5e176f] with keys count : 1

Always, Selected Keys on : [sun.nio.ch.SelectionKeyImpl@5e176f] with keys count : 1, the keycount is always 1. I tried increasing threads, still always its 1.

Can someone respond whats wrong here?

Thanks, Srikanth

有帮助吗?

解决方案

Server socket will accept only one at a time .

When you have multiple sockets on select i.e after accepting a client if you register that socket for OP_READ event then you might get two keys when accept and read event happens on the two socket.

You will get two or more keys selected only when event happens before executing the statement selector.select();

when you are blocking in the select , it will come out after a single event it wont block for multiple events to occur. select() blocks until at least one channel is ready for the events you registered for.

In your case you have registered only one server socket . so you will get only one key . I think this answered your question .

http://tutorials.jenkov.com/java-nio/selectors.html

其他提示

//sc.register(selector, SelectionKey.OP_READ);

This is the line you need. It is commented out. Why?

NB you also need some code to handle OP_READ when you get it, and you need to make it,remove() unconditional and fail-safe. Best way to do that is to move it straight after you call it.next().

I think the main key is that your client is just a thread. althought you have folllow code:

for(int i=0; i<50; i++) {
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.configureBlocking(true);
        //socketChannel.connect(new InetSocketAddress("10.9.242.70", 5555));
        socketChannel.connect(new InetSocketAddress("localhost", 5555));
        channelSet.add(socketChannel);
    }

the 50's request send to server one by one, so your server will accept one by one.

In summary:Server socket will accept only one at a time

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