How do I handle requests asynchronously in a Java server with I / O multiplexing?

Suppose I am writing a Java server that communicates with clients over TCP / IP.

The server is using I/O multiplexing

. There is one thread T0

that waits for selector

and handles client connections. For example, if the connection is ready to read, then T0

reads data from the connection.

Suppose the server has read the incoming request and is now ready to process it. Because processing takes time, the request is processed on a different thread T1

and T0

returned to wait on the selector.

Let's assume that we have T1

finished processing and generated a response. Now I T0

should start writing a response to the client connection. So my question is, how do I T1

post an answer to T0

?

+3


source to share


2 answers


The same thread T1 should read, process and return the result to the client.

Below is an overview of how to do this using the java nio api without tying the number of threads to the number of clients.



**//Thread T0** //wait for selection keys
...
Iterator it = selector.selectedKeys().iterator( );

while (it.hasNext( )) { 
    SelectionKey key = (SelectionKey) it.next();
    // Is a new connection coming in? 
    if (key.isAcceptable( )) {
        ServerSocketChannel server = (ServerSocketChannel) key.channel();
        SocketChannel channel = server.accept()
        // Set the new channel nonblocking
        channel.configureBlocking (false);
        // Register it with the selector
        channel.register (selector, SelectionKey.OP_READ);
    }

    // Is there data to read on this channel?
    if (key.isReadable( )) {
       processRequest (key);
    }

    it.remove( );
}

...

ExecutorService service = Executors.newFixedThreadPool(50);
...
void processRequest(final SelectionKey key) {

    **//Thread T1-T50** //deal with request
    executorService.submit(new Runnable() {            
        SocketChannel channel = (SocketChannel) key.channel();

        //read data from channel, process it and write back to the channel.
    });
)
}

      

+4


source


I recommend using a server thread that does nothing but block on ServerSocket.accept()

and as soon as it accepts a connection, sends it to ExecutorService

. While in theory you can have any number of threads, I would not do that, as it makes your application vulnerable to DoS attacks. Instead, limit the maximum size of the thread pool and reduce it gracefully if the server load exceeds the top.

In fact, there is a small example of how to do this in the documentation for ExecutorService

.

Update: I may have misunderstood your question. As I understand it now, you know the solution suggested above, but want to specifically use synchronous multiplexing .



This will help you understand what service your server is providing, and what is likely the limiting factor (CPU, disk I / O, network, etc.).

You can assign a unique request ID for each incoming connection and insert a handler object into the map under this ID. Then, if the connection becomes ready, the network thread selects the appropriate handler and asks it to accept a certain amount of input / produce a certain amount of output. Whether or not this is applicable to your situation will, of course, depend on the service offered by your server.

+3


source







All Articles