Как сделать этот неблокирующий сервер многопоточным? - PullRequest
4 голосов
/ 26 января 2011

Я пытаюсь разрешить несколько подключений к небольшому приложению типа сервера Java. Он работает нормально, как есть, но если одно соединение открывается, а затем зависает, все последующие соединения будут зависать. Я не уверен, как обрабатывать каждое соединение, до 20 одновременных в их собственном потоке, отслеживая, какой поток принадлежит какому клиенту и т. Д. Код, который у меня пока есть:

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);
    }
}

Ответы [ 3 ]

4 голосов
/ 26 января 2011

Всякий раз, когда мне нужно написать сервер сокетов, я избегаю использования низкоуровневых классов JVM из-за необходимости обрабатывать все мелкие детали.

Вместо этого я использую Apache Mina .Это библиотека Java для написания высокопроизводительных неблокирующих многопоточных серверов с сокетами.

Дополнительным преимуществом использования Mina является то, что он обеспечивает чистую архитектуру (IoFilters, декодеры протоколов), что делает ваш код более модульным и делает его более понятным.

2 голосов
/ 26 января 2011

Если вы действительно не хотите писать сервер NIO в качестве учебного упражнения, я бы порекомендовал использовать Netty .Как и Мина, которую Питер упомянул, это также библиотека для написания высокопроизводительных серверов.

Недавно я перешел от использования собственного кода NIO к этой библиотеке, и это сделало мой код намного чище.

1 голос
/ 26 января 2011

Мое решение - Netty and Executor, который создает ThreadPool. Вы просто добавляете обработчик для конвейера Нетти, который в качестве параметра вызывает executor witch ChannelBuffer. Каждый запрос клиента будет обработан отдельным потоком.

Посмотрите на примеры

...