Java NIO non-blocking: how to refuse incoming connections?

I am trying to use server-side code based on java NIO (without blocking) from the "Java NIO Rox Tutorial". There are many incoming socket connections, and I would like to accept only 100. So if there are 100 active connections, then new ones should be rejected / rejected. But how to do that? There is only a ServerSocketChannel.accept () method that returns a SocketChannel object. Using this object, I can call socketChannel.socket (). Close (), but the connection is already open. Here is the piece of code:

@Override public void run() { while (true) { try { // Wait for an event one of the registered channels this.selector.select(); // Iterate over the set of keys for which events are available Iterator selectedKeys = this.selector.selectedKeys().iterator(); while (selectedKeys.hasNext()) { SelectionKey key = (SelectionKey) selectedKeys.next(); selectedKeys.remove(); if (!key.isValid()) { continue; } // Check what event is available and deal with it if (key.isAcceptable()) { this.accept(key); } else if (key.isReadable()) { this.read(key); } else if (key.isWritable()) { this.write(key); } } } catch (Exception e) { logger.warn("Reading data", e); } } } 

and accept () mehod:

  private void accept(SelectionKey key) throws IOException { // For an accept to be pending the channel must be a server socket channel. ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel(); // Accept the connection and make it non-blocking if (noOfConnections < MAX_CONNECTIONS) { SocketChannel socketChannel = serverSocketChannel.accept(); Socket socket = socketChannel.socket(); socket.setKeepAlive(true); socketChannel.configureBlocking(false); // Register the new SocketChannel with our Selector, indicating // we'd like to be notified when there data waiting to be read socketChannel.register(this.selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);//listener for incoming data: READ from client, WRITE to client noOfConnections++; logger.info("Accepted: " + socket.getRemoteSocketAddress().toString()); } else { // REJECT INCOMING CONNECTION, but how? logger.warn("Server is full: " + noOfConnections + " / " + MAX_CONNECTIONS); } } 

If the connection is not accepted, the accept () method is called again and again.

Thanks for the help!

+4
source share
3 answers

It is impossible to do this, but I doubt what you really want, or at least what you really have to do.

If you want to stop accepting connections, change the percentage in the server socket channel selection group to zero and change it to OP_ACCEPT when you are ready to accept again. At the same time, isAcceptable() will never be true, so the problem you described will not happen.

However, this will not lead to the rejection of further connections: it will simply leave them in the queue for the lag, where, in my opinion, they also belong to TCP designers. When the queue is re-filled, another error will occur: its effect in the client depends on the system: connection failures and / or timeouts.

+1
source

I think that any setting up a queue with a log is unlikely to ever be a good solution. But maybe you can just stop listening.

0
source

Well, I dealt with this problem as follows: Pending-state connections on the socket are a kind of "middle_state", which means that you cannot control / reject them. The backlog socket parameter can be used / ignored / handled differently using a specific virtual machine. This means that you have to accept a specific connection to get the related object and manage it.

Use one thread to accept the connection, pass the received connection to the second thread for processing. Create a variable for the number of active connections. Now that the number of active compounds is less than the desired maximum, accept the connection, increase the number by 1 and go to the second thread for processing. Otherwise, immediately accept the connection and close.

In addition, in the thread of the connection process, than completed, reduce the number of active connections by 1 to the point, there is another free channel.

EDT: just made a stub for server-side machining for Java.Net NIO. Can be adapted for OP needs:

 package servertest; import java.io.IOException; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.util.logging.Level; import java.util.logging.Logger; public class Servertest extends Thread { final int MAXIMUM_CONNECTIONS = 3; int connectionnumber = 0; /** * @param args the command line arguments * @throws java.io.IOException */ public static void main(String[] args){ new Servertest().start(); } @Override public void run() { try { ServerSocket sc = new ServerSocket(33000, 50, InetAddress.getLoopbackAddress()); while (sc.isBound()) { Socket connection = sc.accept(); if(connectionnumber<=MAXIMUM_CONNECTIONS){ new ClientConnection(connection).start(); connectionnumber++; } else { //Optionally write some error response to client connection.close(); } } } catch (IOException ex) { Logger.getLogger(Servertest.class.getName()).log(Level.SEVERE, null, ex); } } private class ClientConnection extends Thread{ private Socket connection; public ClientConnection(Socket connection) { this.connection=connection; } @Override public void run() { try { //make user interaction connection.close(); } catch (IOException ex) { Logger.getLogger(Servertest.class.getName()).log(Level.SEVERE, null, ex); } connectionnumber--; } } } 
0
source

All Articles