Различают сообщения, отправленные от КЛИЕНТА и других

1

Я использую SocketChannel и Selector для записи сервера. Задача серверов - позволить клиентам подключаться, читать сообщения от клиентов и писать сообщения клиентам.

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

ех. Когда клиент подключается, я заметил, что инструкция чтения выполнена без отправки клиентом каких-либо данных. Это важно, потому что после того, как сервер прочитал сообщение от клиента, он должен добавить это сообщение в очередь сообщений. Это сообщение будет удалено и обработано из очереди внешним приложением. Проблема в том, что каждый раз, когда происходит чтение, эти еще UFM (неопознанные сообщения) нарушают внешнее приложение при попытке их декодирования.

Прошу прощения, если на этот вопрос уже был дан ответ. Я не нашел полного ответа.

Вот мой метод accept, который, если я не ошибаюсь, сообщает селектору уведомлять нас, когда данные доступны для чтения.

private void accept(SelectionKey key) throws IOException {
    ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();

    // Accept the connection and make it non-blocking
    SocketChannel socketChannel = serverSocketChannel.accept();
    socketChannel.configureBlocking(false);

    socketChannel.register(this.selector, SelectionKey.OP_READ);
}

Вот метод выбора, который ждет события.

while (should_run) {
    try {
        //Load all pending operations to key
        while (!operations.isEmpty()) {
            SelectionKey key = client.keyFor(getSelector());
            if (!key.isValid()) {
                operations.remove();
                throw new Exception("Key not valid");
            }
            key.interestOps(operations.remove());
        }

        selector.select();

        Iterator selectedKeys = selector.selectedKeys().iterator();
        while (selectedKeys.hasNext()) {
            SelectionKey key = (SelectionKey) selectedKeys.next();
            //Check if key is valid
            if (!key.isValid()) {
                throw new Exception("Key not valid");
            }

            if (key.isAcceptable()) {
                accept(key);
            } else if (key.isReadable()) {
                read(key);
            } else if (key.isWritable()) {
                write(key);
            }

            selectedKeys.remove();
        }
    } catch (Exception e) {
        System.err.println("Something went wrong: " + e.getMessage());
        e.printStackTrace();
    }
}

Вот функция чтения, называемая if key.isReadable()

private void read(SelectionKey key) {     
    System.out.println("Read fired");

    //Clear the buffer for new Data
    this.readBuffer.clear();

    int count;
    try {
        count = this.client.read(this.readBuffer);
        if (count == -1) {
            throw new IOException("Socket closed");
        }
    } catch (IOException e) {
        key.cancel();
        return;
    }

    //PROBLEM OCCURRING HERE
    this.worker.give(this.readBuffer.array(), count);
}

Чтение должно читать сообщения и передавать сообщение в рабочий поток, где сообщение декодируется, и с ним происходят другие приятные вещи.

Метод read вызывается после каждого подключения нового клиента. Счет обычно мал, между 4 и 10, и когда я декодирую с использованием new String(data[], "UTF-8"), он оказывается японским или что-то в этом роде.

Я проверил это, просто распечатывая count каждый раз, когда вызывается чтение.

Эту проблему можно решить, просто проверив размер каждого входящего сообщения и игнорируя те, которые являются малыми. Но похоже, что это может иметь неприятные последствия, если происходит фрагментация.

EDIT: Код примера клиента:

Socket socket = new Socket("localhost", 3000);
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
while (true) {
    String input = JOptionPane.showInputDialog("Send something to the server");
    if (input == null)
            break;
    oos.writeObject(input);
}

ПРИМЕЧАНИЕ. У меня нет исходного кода для однорангового узла, но этот пример VERY SIMPLE дает точные результаты. Прежде чем MessageDialog даже предложит отправить сообщение на сервер, сообщение будет получено сервером, либо японским, либо рядом вопросительных знаков (??????).

  • 0
    «У меня возникают некоторые трудности при различении сообщений, отправленных клиентом, и других данных, которые запускают инструкцию чтения». Что читать инструкцию? На канале нет других данных, кроме того, что отправляет узел. «Когда клиент подключается, я заметил, что инструкция чтения выполнена без отправки клиентом каких-либо данных». Пожалуйста, объясните, показывая код, который демонстрирует это предполагаемое поведение.
  • 0
    @EJP Я добавил больше кода. Когда я говорю «чтение инструкции», я имею в виду, что key.isReadable() имеет значение true и вызывает функцию, которую я использую для чтения из SocketChannel
Показать ещё 5 комментариев
Теги:
nio
socketchannel

1 ответ

1
Лучший ответ

и другие данные, которые отключают инструкцию чтения.

Других данных нет. Только данные от клиента.

'new ObjectOutputStream()' записывает заголовок потока, который начинается с 0xAC. Это то, что вы читаете.

Поскольку peer использует потоки объектов, вы должны использовать блокирующие сокеты, потоки и потоки ввода объектов. Не NIO.

Член 'this.client' должен быть удален в соответствии с моими комментариями выше. Предполагается, что у вас есть только один клиент.

Закрытие канала отменяет ключ. Вы редко когда-либо нуждаетесь в key.cancel(). Я никогда не использую его.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню