17

在阅读 Netty 教程时,我发现了一个关于如何集成 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;
    }

}

(请看一下 line 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()));

还是其他技术?非常感谢。

4

7 回答 7

6

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

于 2011-10-18T20:35:19.300 回答
3

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

  • 可序列化是省力的,但性能最差(序列化所有内容)。
  • Protobuf 是工作量和性能之间的良好权衡(需要 .proto 维护)
  • Externalizable 需要付出很大的努力,但性能最好(自定义最小编解码器)

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

于 2011-11-15T18:42:14.833 回答
2

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

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

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

于 2011-10-18T14:20:56.010 回答
2

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

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

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

于 2013-02-25T13:57:30.190 回答
1

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

于 2011-11-05T17:57:42.217 回答
0

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

于 2014-04-18T08:49:48.740 回答
0

经过长期的研究和痛苦......我想出了将消息组合到一个包装消息中的想法。在该消息中,我使用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
}
于 2017-04-27T09:39:43.543 回答