Netty + ProtoBuffer: несколько сообщений связи для одного соединения - PullRequest
15 голосов
/ 18 октября 2011

Читая учебник Netty, я нашел простое описание того, как интегрировать 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() метод.Таким образом, в этой ситуации я могу использовать ONE сообщение для отправки на сервер и ONE сообщение для получения от сервера, и это плохо для меня, и я думаю, что не только для меня :( КакМогу ли я использовать разные сообщения для и от одного соединения? Возможно, я смогу создать несколько 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()));

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

Ответы [ 7 ]

5 голосов
/ 19 октября 2011

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

3 голосов
/ 15 ноября 2011

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

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

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

2 голосов
/ 25 февраля 2013

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

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

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

2 голосов
/ 18 октября 2011

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

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

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

1 голос
/ 05 ноября 2011

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

0 голосов
/ 27 апреля 2017

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

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
}
0 голосов
/ 18 апреля 2014

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

...