бесконечный цикл с селектором Java - PullRequest
2 голосов
/ 14 февраля 2011

Я новичок в Java, теперь я озадачен селектором java nio, ниже приведен код из книги 3-й сетевой программы java,

package org.eclipse.java.socket.samples;

import java.io.IOException;
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;

public class ChargenServer {
    public static int DEFAULT_PORT = 4321;
    public static void main(String[] args) {
        int port;
        try {
            port = Integer.parseInt(args[0]);
        }
        catch (Exception ex) {
            port = DEFAULT_PORT;
        }
        System.out.println("Listening for connections on port " + port);
        byte[] rotation = new byte[95 * 2];
        for (byte i = ' '; i <= '~'; i++) {
            rotation[i - ' '] = i;
            rotation[i + 95 - ' '] = i;
        }
        ServerSocketChannel serverChannel;
        Selector selector;
        try {
            serverChannel = ServerSocketChannel.open();
            ServerSocket ss = serverChannel.socket();
            InetSocketAddress address = new InetSocketAddress(port);
            ss.bind(address);
            serverChannel.configureBlocking(false);
            selector = Selector.open();
            serverChannel.register(selector, SelectionKey.OP_ACCEPT);
        }
        catch (IOException ex) {
            ex.printStackTrace();
            return;
        }
        while (true) {
            try {
                selector.select();
            }
            catch (IOException ex) {
                ex.printStackTrace();
                break;
            }            
            Set<SelectionKey> readyKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = readyKeys.iterator();
            while (iterator.hasNext()) {
                SelectionKey key = (SelectionKey) iterator.next();
                iterator.remove();
                try {
                    if (key.isAcceptable()) {
                        ServerSocketChannel server = (ServerSocketChannel) key
                                .channel();
                        SocketChannel client = server.accept();
                        System.out
                                .println("Accepted connection from " + client);
                        client.configureBlocking(false);
                        SelectionKey key2 = client.register(selector,
                                SelectionKey.
                                OP_WRITE);
                        ByteBuffer buffer = ByteBuffer.allocate(74);
                        buffer.put(rotation, 0, 72);
                        buffer.put((byte) '\r');
                        buffer.put((byte) '\n');
                        buffer.flip();
                        key2.attach(buffer);
                    }
                    else if (key.isWritable()) {
                        SocketChannel client = (SocketChannel) key.channel();
                        ByteBuffer buffer = (ByteBuffer) key.attachment();
                        if (!buffer.hasRemaining()) {
                            // Refill the buffer with the next line
                            buffer.rewind();
                            // Get the old first character
                            int first = buffer.get();
                            // Get ready to change the data in the buffer
                            buffer.rewind();
                            // Find the new first characters position in
                            // rotation
                            int position = first - ' ' + 1;
                            // copy the data from rotation into the buffer
                            buffer.put(rotation, position, 72);
                            // Store a line break at the end of the buffer
                            buffer.put((byte) '\r');
                            buffer.put((byte) '\n');
                            // Prepare the buffer for writing
                            buffer.flip();
                            buffer.compact();
                        }
                        client.write(buffer);
                    }
                }
                catch (IOException ex) {
                    key.cancel();
                    try {
                        key.channel().close();
                    }
                    catch (IOException cex) {
                    }
                }
            }
        }
    }
}

Сервер довольно прост, получитеподключение, затем эхо последовательных писем клиентам, но когда я запускаю его на своем Ubuntu10.10 с

Java-версией "1.6.0_20"

OpenJDK Runtime Environment (IcedTea6 1.9.4)(6b20-1.9.4-0ubuntu1)

Серверная виртуальная машина OpenJDK (сборка 19.0-b09, смешанный режим)

У меня бесконечный цикл, я действительно не знаю почему, помогите мне, пожалуйста!

Спасибо всем, но я все еще путаюсь с селектором, теперь давайте сделаем вещи проще, чтобы показать мой смущенный, см. Код:

package org.eclipse.java.socket.selector;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class SocketSelector {
    public static void main(String[] args) throws IOException {
        // Create selector
        Selector selector = null;
        selector = Selector.open();
        ////////////////////////////////////////////////////////////////////////
        SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress(
                "localhost", 4321));
        socketChannel.configureBlocking(false);
        socketChannel.register(selector, SelectionKey.OP_CONNECT);
        /*
         * Let's begin select
         */
        while (true) {
            selector.select();
            System.out.println("Hello, selector!");
            Set readyKeys = selector.selectedKeys();
            Iterator it = readyKeys.iterator();  
            while (it.hasNext()) {
                SelectionKey key = (SelectionKey )it.next();
                if (key.isReadable()) {
                    System.out.println("It's readable!");
                }
                it.remove();
            }
        }
    }
}

в моем понимании, "selector.select () "дождаться входного события с удаленного сервера, затем it.remove () удалить это событие, поэтому селектор начинает ожидать нового события с удаленного сервера, поэтому клиент может непрерывно получать данные с сервера с помощью селектора, норезультат повторяется снова и снова, селектор мне имеет никакого смысла к данным сервера, почему?Что-то не так с моим кодом?

Ответы [ 2 ]

1 голос
/ 14 февраля 2011

Три вопроса с кодом, в т.ч. не закрывать селекторы.

Вам необходимо зарегистрироваться только на OP_WRITE , если при операции записи не удается записать весь буфер, и отменить регистрацию в противном случае. Посмотрите на interestedOps().

Как правило, вам нужно OP_READ для чтения с этого канала. Наконец ВСЕГДА проверьте http://bugs.sun.com перед переполнением стека (это одна из моих отслеживаемых ошибок). Совет: не используйте тот же селектор для принятия / записи.

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4919127

ура

1 голос
/ 14 февраля 2011

После того, как вы написали все, что хотите (то есть, когда внешний буфер пуст), вы должны удалить флаг интереса OP_WRITE.

...