【问题标题】:Netty + ProtoBuffer: A few communication messages for one connectionNetty + ProtoBuffer:一个连接的几个通信消息
【发布时间】:2011-10-18 07:43:09
【问题描述】:

在阅读 Netty 教程时,我发现了一个简单的 description 如何集成 Netty 和 Google Protocol Buffers。我已经开始研究它的示例(因为文档中没有更多信息)并编写了一个简单的应用程序,例如示例本地时间应用程序。但是这个例子是在 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()));

或其他技术? 非常感谢。

【问题讨论】:

  • 您可以在管道中添加许多解码器/编码器,但它们应该能够传递他们不知道如何处理的数据。看着netty source at github 好像不是这样的。所以可能有办法做到这一点,但我怀疑它是否简单。无论如何尝试并分享结果:)
  • @Slartibartfast 是的,这并不简单,需要努力工作:(

标签: java static protocol-buffers netty


【解决方案1】:

我在google groups找到了netty的作者的帖子,并且明白我必须改变我的架构或编写我自己的解码器,就像我上面写的那样,所以,开始思考什么方法会更简单更好。

【讨论】:

  • 我认为该组线程的重点是,如果您想发送多种类型的消息,解决方案是在 protobuf 中定义 1 个通用“消息容器”(比如说ProtocolMessage)将包含 1 种或多种不同类型的消息。然后,您将对 ProtocolMessage 消息类型使用 protobuf 解码器,并将任何进一步的解释留给 Netty 中的消息处理程序。
【解决方案2】:

如果您仍然要编写自己的编解码器,您可能需要考虑为自定义数据对象实现 Externalizable 接口。

  • Serializable 工作量不大,但性能最差(对所有内容进行序列化)。
  • Protobuf 是工作量和性能之间的良好权衡(需要 .proto 维护)
  • Externalizable 工作量大,但性能最佳(自定义最小编解码器)

如果您已经知道您的项目必须像山羊一样扩展,那么您可能不得不走这条艰难的道路。 Protobuf 不是灵丹妙药。

【讨论】:

    【解决方案3】:

    理论上,这可以通过修改每个传入消息的管道以适应传入消息来完成。看看 Netty 中的 port unification 示例。

    顺序是:
    1) 在帧解码器或其他“DecoderMappingDecoder”中检查传入消息的消息类型
    2)如示例所示动态修改管道

    但为什么不使用不同的连接并遵循以下顺序:
    1) 仅根据传入消息在管道中添加其他解码器一次。
    2) 添加 same 通道上游处理程序实例作为管道中的最后一个处理程序,这样所有消息都会路由到同一个实例,这几乎就像有一个单一的连接。

    【讨论】:

    • 理论上我们应该修改解码器以从字节流中读取一些 id 并选择正确的算法进行解码,我不知道这个解决方案,但这不是简单或好的方法。为什么我只想打开一个连接,因为我想设置我的客户端并准备与服务器的连接并使用这个(只是一个)连接将所有消息发送到服务器,消息之类的操作和当前架构为我提供了可能性每次操作都创建很多客户端,我觉得不是个好主意!
    • 如果您有 n 种消息类型和 n 种不同的解码方式,那么您仍然可以使用具有单个“MappingDecoder”的相同连接,该连接将检查消息类型并将其传递给正确的解码器进行解码。看看 netty 嵌入式解码器(grepcode.com/file/repository.jboss.org/maven2/org.jboss.netty/…),它可以为您提供一种在不使用管道的情况下使用解码器的方法。
    【解决方案4】:

    问题是没有办法以二进制格式区分两个不同的 protobuf 消息。但是有办法在protobuf文件中解决:

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

    未设置的可选字段不会产生开销。此外,您可以添加一个 Enum,但这只是一个奖励。

    【讨论】:

      【解决方案5】:

      问题不完全是 Netty 限制或编码器/解码器限制。问题是 Google Protocol Buffers 只提供了一种序列化/反序列化对象的方法,但没有提供协议。他们有某种 RPC 实现作为标准分发的一部分,但是如果你尝试实现他们的 RPC 协议,那么你最终会得到 3 层间接。 我在其中一个项目中所做的是定义一个基本上是消息联合的消息。此消息包含一个字段,即类型和另一个字段,即实际消息。你仍然会得到 2 个间接层,但不是 3 个。这样,Netty 中的示例将适用于你,但正如在前一篇文章中提到的,你必须在业务逻辑处理程序中放入更多逻辑。

      【讨论】:

        【解决方案6】:

        您可以使用消息隧道将各种类型的消息作为有效负载发送到单个消息中。 希望对你有帮助

        【讨论】:

          【解决方案7】:

          经过长期的研究和痛苦... 我想出了将消息组合到一个包装消息中的想法。在该消息中,我使用 oneof 键将允许对象的数量限制为 the 只有一个。查看示例:

          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
          }
          

          【讨论】:

            猜你喜欢
            • 2014-10-08
            • 2018-09-15
            • 2012-08-18
            • 2012-02-15
            • 1970-01-01
            • 2014-03-21
            • 2017-07-02
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多