Netty + ProtoBuffer:一个连接的一些通信消息

时间:2011-10-18 07:43:10

标签: java static protocol-buffers netty

在阅读Netty教程时,我发现了如何整合Netty和description的简单Google Protocol Buffers。我已经开始调查它的示例(因为文档中没有更多信息)并编写了一个简单的应用程序,如示例本地时间应用程序。但是这个例子是在PipeFactory Class中使用静态初始化,例如:

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 个答案:

答案 0 :(得分:5)

我在google groups找到了netty作者的帖子并明白我必须改变我的架构或编写我自己的解码器,如上所述,所以,开始思考哪种方式会更容易和更好。

答案 1 :(得分:3)

如果您打算编写自己的编解码器,您可能希望查看为自定义数据对象实现Externalizable接口。

  • Serializable是省力的,但性能最差(序列化所有内容)。
  • Protobuf是努力与绩效之间的良好平衡(需要.proto维护)
  • 可外部化是高成本,但最佳性能(自定义最小编解码器)

如果你已经知道你的项目必须像山羊一样扩展,你可能必须走艰难的道路。 Protobuf不是银弹。

答案 2 :(得分:2)

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

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

所示

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

答案 3 :(得分:2)

问题在于无法以二进制格式将两个不同的protobuf消息彼此区分开来。但是有一种方法可以在protobuf文件中解决它:

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

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

答案 4 :(得分:1)

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

答案 5 :(得分:0)

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

答案 6 :(得分: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
}