Netty NIO: чтение полученных сообщений

Я разрабатываю клиентскую и серверную систему связи с использованием Netty NIO в Java. Мой код можно найти в следующее хранилище. В настоящее время у меня есть один сервер и два клиента, и я отправляю информацию с сервера клиентам и наоборот.

что я пытаюсь выяснить, когда я получаю сообщение от первого клиента на сервер, как я могу отправить это сообщение второму клиенту (и наоборот от клиента 2 к клиенту 1). Как могу ли я отправить сообщение конкретному клиенту?

Я заметил, что мои проблемы возникли из-за того, что я пытаюсь отправить сообщения с сервера. Мой код в serverHandler следующий:

for (Channel ch : channels1) {
    responseData.setIntValue(channels1.size());
    remoteAddr.add(ch.remoteAddress().toString());
    future = ch.writeAndFlush(responseData);
    //future.addListener(ChannelFutureListener.CLOSE);
    System.out.println("the requested data from the clients are: "+requestData);
    responseData1.setStringValue(requestData.toString());
    future = ch.writeAndFlush(responseData1);
    System.out.println(future);
}

по умолчанию я отправляю сообщение о количестве подключений, но также, когда я получаю сообщение от клиента 1 или 2, я хочу отправить его обратно в 2 и 1. Поэтому я хочу выполнить связь между двумя компонентами. Как я могу отправить из сервер для конкретного клиента? Я не уверен, как я могу отправлять сообщения обратно клиенту.

1 ответов


общий подход

давайте опишем подход к проблеме.

при получении данных на стороне сервера используйте удаленный адрес канала (java.net.SocketAddress Channel.remoteAddress() метод) для идентификации клиента.

такая идентификация может быть сделана с помощью карты, такой как:Map<SocketAddress, Client>, где Client класс или интерфейс должны содержать соответствующий контекст, связанный с клиентским подключением (каналом), включая его Channel. Обязательно держите карту обновление: соответствующим образом обрабатывайте события" клиент подключен "и" клиент отключен".

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

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

Netty-специфическое решение

давайте рассмотрим реализацию на стороне сервера, в частности, реализацию ProcessingHandler класса.

он уже управляет активными каналами, представляя их как группу каналов:

static final ChannelGroup channels1 =
    new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

ведение группы канала вверх-к-дата

текущая реализация обрабатывает событие" канал становится активным", чтобы сохранить группу каналов в актуальном состоянии:

@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
    channels1.add(ctx.channel());
    // ...
}

но это только половина: необходимо обрабатывать " канал становится событие "inactive" также симметрично. Реализация должна выглядеть так:

@Override
public void channelInactive(final ChannelHandlerContext ctx) throws Exception {
    channels1.remove(ctx.channel());
}

Broadcasting: отправка полученного сообщения на все каналы, кроме текущего

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

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    // ...

    for (Channel ch : channels1) {
        // Does `ch` represent the channel of the current sending client?
        if (ch.equals(ctx.channel())) {
            // Skip.
            continue;
        }

        // Send the message to the `ch` channel.
        // ...
    }

    // ...
}

отправка и получение проблема string

в настоящее время функции вокруг ResponseData класса нет (не реализовать.)

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

  1. на ResponseData класс:getStringValue и toString методы должны быть исправлены:

    String getStringValue() {
        return this.strValue;
    }
    
    @Override
    public String toString() {
        return intValue + ";" + strValue;
    }
    
  2. на ResponseDataEncoder class: он должен использовать строковое значение:

    private final Charset charset = Charset.forName("UTF-8");
    
    @Override
    protected void encode(final ChannelHandlerContext ctx, final ResponseData msg, final ByteBuf out) throws Exception {
        out.writeInt(msg.getIntValue());
        out.writeInt(msg.getStringValue().length());
        out.writeCharSequence(msg.getStringValue(), charset);
    }
    
  3. на ResponseDataDecoder class: он должен использовать строку значение:

    private final Charset charset = Charset.forName("UTF-8");
    
    @Override
    protected void decode(final ChannelHandlerContext ctx, final ByteBuf in, final List<Object> out) throws Exception {
        ResponseData data = new ResponseData();
        data.setIntValue(in.readInt());
        int strLen = in.readInt();
        data.setStringValue(in.readCharSequence(strLen, charset).toString());
        out.add(data);
    }
    
  4. на ClientHandler класс: он должен правильно получать и обрабатывать сообщение:

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        final ResponseData responseData = (ResponseData) msg;
        System.out.println("The message sent from the server " + responseData);
        update.accept(responseData.getIntValue());
    }
    

дополнительная литература

  1. "SecureChat-сервер чата на основе TLS, полученный из примера Telnet", Netty Documentation. В частности, реализация SecureChatServerHandler класс.
  2. "Нетти в действии", Норман Маурер, Марвин Аллен Wolfthal (ISBN-13: 978-1617291470)," Часть 3 - сетевые протоколы", подкаптер" 12.2 наш пример приложения WebSocket". Охватывает реализацию "браузерного чат-приложения".