Netty + Protobuffer: несколько сообщений общения для одного соединения

StackOverflow https://stackoverflow.com/questions/7803966

Вопрос

Читая учебное пособие Netty, я нашел простой описание как интегрировать Нетти и Буферы протокола Google. Анкет Я начал исследовать его пример (потому что в документации больше нет информации) и написал простое приложение, подобное примеру локального времени. Но этот пример использует статическую инициализацию в классе PipeFactory, например:

import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.handler.codec.protobuf.ProtobufDecoder;
import org.jboss.netty.handler.codec.protobuf.ProtobufEncoder;
import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;

import static org.jboss.netty.channel.Channels.pipeline;

/**
 * @author sergiizagriichuk
 */
class ProtoCommunicationClientPipeFactory implements ChannelPipelineFactory {

    public ChannelPipeline getPipeline() throws Exception {
        ChannelPipeline p = pipeline();
        p.addLast("frameDecoder", new ProtobufVarint32FrameDecoder());
        p.addLast("protobufDecoder", new ProtobufDecoder(Communication.DataMessage.getDefaultInstance()));

        p.addLast("frameEncoder", new ProtobufVarint32LengthFieldPrepender());
        p.addLast("protobufEncoder", new ProtobufEncoder());

        p.addLast("handler", new ProtoCommunicationClientHandler());
        return p;
    }

}

(Посмотрите на линию p.addLast("protobufDecoder", new ProtobufDecoder(Communication.DataMessage.getDefaultInstance()));) и только одна фабрика может быть создана (насколько я понимаю) для ClientBootstrap класс, я имею в виду bootstrap.setPipelineFactory() метод Итак, в этой ситуации я могу использовать ОДИН Сообщение для отправки на сервер и ОДИН Сообщение для получения с сервера, и это плохо для меня, и я думаю, что не только для меня :( Как я могу использовать разные сообщения для и обратно только для одного соединения? Возможно, я могу создать несколько protobufDecoder как это

p.addLast("protobufDecoder", new ProtobufDecoder(Communication.DataMessage.getDefaultInstance()));
p.addLast("protobufDecoder", new ProtobufDecoder(Communication.TestMessage.getDefaultInstance()));
p.addLast("protobufDecoder", new ProtobufDecoder(Communication.SrcMessage.getDefaultInstance()));

или другие методы? Большое спасибо.

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

Решение

Я нашел ветку автора Нейти в Группы Google и понял, что я должен изменить свою архитектуру или написать свой собственный декодер, как я писал выше, поэтому начните думать, какой путь будет легко и лучше.

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

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

  • Serializable с низкой температурой, но худшая производительность (сериализует все).
  • Protobuf-это хороший компромисс между усилиями и производительностью (требует технического обслуживания.
  • Extraizable - это высокие усилия, но лучшая производительность (пользовательские минимальные кодеки)

Если вы уже знаете, что ваш проект должен будет масштабироваться, как горная коза, вам, возможно, придется идти по жесткой дороге. Protobuf не серебряная пуля.

Теоретически это можно сделать путем изменения конвейера для каждого входящего сообщения в соответствии с входящим сообщением. Взглянуть на Объединение порта Пример в Нетти.

Последовательность будет:
1) В кадре декодера или в другом «декодермапиндере -рекодере» вы проверяете тип сообщения входящего сообщения
2) Динамически изменить трубопровод, как показано в примере

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

Проблема в том, что нет никакого способа отличить два разных сообщения протобуфа друг от друга в двоичном формате. Но есть способ решить его в файле Protobuf:

message AnyMessage {
    message DataMessage { [...] }
    optional DataMessage dataMessage = 1;
    message TestMessage { [...] }
    optional TestMessage testMessage = 2;
    message SrcMessage { [...] }
    optional SrcMessage srcMessage = 3;
}

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

Проблема не совсем ограничение нетти или ограничение кодера/декодера. Проблема заключается в том, что буферы протокола Google предлагают просто способ сериализации/десериализации объектов, но не предоставляют протокол. У них есть какая -то реализация RPC в рамках стандартного распределения, но если вы попытаетесь реализовать их протокол RPC, то вы получите 3 уровня косвенности. То, что я сделал в одном из проектов, было определить сообщение, которое в основном является союзом сообщений. Это сообщение содержит одно поле, которое является типом, и другое поле, которое является фактическим сообщением. Вы по-прежнему в конечном итоге вы получите 2 слоя.

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

После долгих исследований и страданий ... я придумал идею использования композиции сообщений в одном сообщении обертки. Внутри этого сообщения я использую один из ключ, чтобы ограничить количество разрешенных объектов а только один. Оформить пример:

message OneMessage {
    MessageType messageType = 1;

    oneof messageBody {
        Event event = 2;
        Request request  = 3;
        Response response = 4;
    }

    string messageCode = 5; //unique message code
    int64 timestamp = 6; //server time
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top