4

I'm trying to allow multiple connections to a little Java server type app. It works fine as is, but if one connection opens and then hangs, all subsequent connections will hang. I'm not sure how to go about handling each connection, up to about 20 concurrent ones in their own thread while keeping track of which thread belongs to which client etc. The code I have so far is:

private void init() {
    try {
        // Create the server socket channel
        ServerSocketChannel server = ServerSocketChannel.open();
        // nonblocking I/O
        server.configureBlocking(false);
        // host-port 
        server.socket().bind(new InetSocketAddress(host, port));
        System.out.println("Server connected on " + host + ":" + port);
        // Create the selector
        Selector selector = Selector.open();
        // Recording server to selector (type OP_ACCEPT)
        server.register(selector, SelectionKey.OP_ACCEPT);
        // Infinite server loop
        for (;;) {
            // Waiting for events
            selector.select();
            // Get keys
            Set keys = selector.selectedKeys();
            Iterator i = keys.iterator();
            // For each keys...
            while (i.hasNext()) {
                SelectionKey key = (SelectionKey) i.next();
                // Remove the current key
                i.remove();
                // if isAccetable = true
                // then a client required a connection
                if (key.isAcceptable()) {
                    // get client socket channel
                    SocketChannel client = server.accept();
                    // Non Blocking I/O
                    client.configureBlocking(false);
                    // recording to the selector (reading)
                    client.register(selector, SelectionKey.OP_READ);
                    continue;
                }
                // then the server is ready to read
                if (key.isReadable()) {
                    SocketChannel client = (SocketChannel) key.channel();
                    // Read byte coming from the client
                    int BUFFER_SIZE = 32;
                    ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
                    try {
                        client.read(buffer);
                    } catch (Exception e) {
                        // client is no longer active
                        e.printStackTrace();
                        continue;
                    }
                    buffer.flip();
                    Charset charset = Charset.forName("ISO-8859-1");
                    CharsetDecoder decoder = charset.newDecoder();
                    CharBuffer charBuffer = decoder.decode(buffer);
                    Handler dataHandler = new Handler();
                    client.write(ByteBuffer.wrap(dataHandler.processInput(charBuffer.toString()).getBytes()));
                    client.socket().close();
                    continue;
                }
            }
        }
    } catch (IOException ex) {
        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
    }
}
user183037
  • 2,549
  • 4
  • 31
  • 42
zcourts
  • 4,863
  • 6
  • 49
  • 74
  • I would just use blocking NIO and have one thread per client, it will be much simpler and can scale up to 10K connections. It can also be more efficient. – Peter Lawrey Jan 26 '11 at 09:18

3 Answers3

4

Whenever I need to write a socket server I avoid using low-level JVM classes because of the need to handle all the nitty-gritty details.

Instead I use Apache Mina. This ia a Java library for writing high-performance non-blocking multi-threaded socket servers.

An added benefit of using Mina is that it enforces clean architecture (IoFilters, protocol decoders) which makes your code more modular and makes it more maintainable.

Peter Knego
  • 79,991
  • 11
  • 123
  • 154
  • Sounds very promising...I'll take a look and get back. I really need to familiarise myself with more of the Apache projects... – zcourts Jan 26 '11 at 09:27
2

Unless you really want to write an NIO server as a learning exercise I would recommend using Netty. Like Mina that Peter mentioned it is also a library for writing high performance servers.

I recently moved from using my own NIO code to this library and it has made my code so much cleaner.

Mark
  • 28,783
  • 8
  • 63
  • 92
  • I'm all for anything that'll make life simpler without too much overhead so I'll checkout netty as well – zcourts Jan 26 '11 at 12:41
1

My solution i Netty and Executor which creates ThreadPool. You simply add handler do Netty's pipeline, which call executor witch ChannelBuffer as a parameter. Than every client request will be processed by separate thread.

Look at the examples

  • Went with netty in the end, no external deps. and seem to fit in quite nicely, how steep a learning curve is it for getting into the API? – zcourts Jan 26 '11 at 21:36
  • You will be able to make basic server on a minute, but it's good to deep into netty sources to know how it works. It was good lesson for me :) I recommend to read about build in handlers - decoders / encoders. I build my server just adding a few classes into pipeline. HTTP, SSL, whatever you want :) – Marcin Kacperek Jan 27 '11 at 07:22
  • 1
    Here you have good comparison Netty vs Mina: http://stackoverflow.com/questions/1637752/netty-vs-apache-mina – Marcin Kacperek Jan 27 '11 at 09:35