Вопрос

Привет, я пытаюсь реализовать простой сервер Java NIO;который регистрирует сокетChannel с помощью селектора.Следовательно, я хочу послушать клиента и отправить ответ обратно.После того, как сокет-канал зарегистрирован в селекторе, даже если клиент (не 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");

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

Это было полезно?

Решение

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

Также это плохая идея сделать selector статический.

Другие советы

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

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 и запустить процесс принятия на ServerSocket в том же потоке, что и чтение/запись.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top