Сервер NIO не может прослушивать клиента - PullRequest
1 голос
/ 25 мая 2009

Привет, я пытаюсь реализовать простой сервер Java NIO; который регистрирует socketChannel с помощью селектора. Поэтому я хочу выслушать клиента и отправить ответ. После того как socketChannel зарегистрирован в селекторе, даже если клиент (не NIO) отправляет некоторые данные, Сервер не может читать; Однако сгенерированный ключ все еще повторяется.

Детальный просмотр: Сторона сервера:

**First thread**:

public void run () { while (true) {

    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
    serverSocketChannel.configureBlocking(true);
    serverSocketChannel.socket().bind(inetAdressOfServer);
    SocketChannel clientChannel = serverSocketChannel.accept();
    new Listener("").addSocketChannel(clientChannel);

}}

**Second Thread**:

    static Selector selector = Selector.open();
    public boolean addSocketChannel(SocketChannel clientChannel) {

        SelectionKey key = clientSocketChannel.register(selector, selector.OP_READ|SelectionKey.OP_WRITE);              
        key.attach(new ChannelCallback(clientSocketChannel));
        return key.isValid();
    }

    public void run() {

        Set keysSet = selector.keys();
        Iterator i = keysSet.iterator();        
        while (i.hasNext()) {
            SelectionKey key = (SelectionKey) i.next();
        }

        if (key.isReadable()) {
            //read and do something
        }
    }



Client Side:

Socket socket = new Socket(serverIP, serverPort);    
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());    
dos.writeBytes(str + "\n");

NB. Когда выполняется в одном потоке, работает та же самая программа, но при реализации вышеупомянутым способом она не слушает клиента. Пожалуйста, помогите мне решить эту проблему.

Ответы [ 2 ]

1 голос
/ 25 мая 2009

Чтение работает чтение из другого потока, вот очевидные проблемы с вашим кодом.

public void run() {
    Set keysSet = selector.keys();

Здесь вы берете набор ключей из итератора, но в селекторе нет кода, выполняющего select () или selectNow (), поэтому этот набор всегда будет пустым.

    Iterator i = keysSet.iterator();        
    while (i.hasNext()) {
        SelectionKey key = (SelectionKey) i.next();
    }
    if (key.isReadable()) {
        //read and do something
    }
}

Это даже не компилируется, проверка «чтения» на ключе должна выполняться внутри блока while.

SelectionKey key = clientSocketChannel.register(selector,
                                                SelectionKey.OP_READ | 
                                                SelectionKey.OP_WRITE);              

Две проблемы: канал должен быть установлен в неблокирующем режиме, прежде чем это будет сделано, и SelectionKey.OP_WRITE не должен быть установлен, если вы не хотите, чтобы ключ возвращался каждый раз, когда вы запускаете выбор.

Вы должны установить SelectionKey.OP_WRITE, только если вы действительно планируете сделать запись.

Наконец, использование двух потоков здесь очень нетрадиционно. Рекомендуемый способ сделать это состоит в том, чтобы зарегистрировать ServerSocketChannel в селекторе с помощью OP_ACCEPT и выполнить команду accept для ServerSocket в том же потоке, что и чтение / запись.

1 голос
/ 25 мая 2009

Очень трудно увидеть, что вы там сделали, но похоже, что то, что вы пометили как «второй поток», используется обоими потоками (некоторая путаница по поводу реализации Runnable / расширение Thread и реальных потоков? ). В частности, я предполагаю, что new Listener создает и запускает поток. Затем вы звоните addSocketChannel в первом потоке. Следовательно, есть состояние гонки.

Также плохая идея сделать selector статичным.

...