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

发布于 2024-12-10 15:05:08 字数 2195 浏览 0 评论 0原文

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

也许我可以像这样或其他技术 ? 多谢。

While reading the Netty tutorial, I've found a simple description of how to integrate Netty and Google Protocol Buffers. I've started to investigate its example (because there is no more information in the documentation) and written a simple application like the example local time application. But this example is using static initialization in PipeFactory Class, e.g.:

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;
    }

}

(Please take a look at line p.addLast("protobufDecoder", new ProtobufDecoder(Communication.DataMessage.getDefaultInstance()));)
and just one factory can be created (as I understand) for ClientBootstrap class, I mean bootstrap.setPipelineFactory() method. So, in this situation I can use ONE message to send to server and ONE message to receive from server and it is bad for me, and I think not just for me :( How can I use different messages to and from for just one connection?
Perhaps I can create a few protobufDecoder like this

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

or other techniques?
Thanks a lot.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

薄暮涼年 2024-12-17 15:05:08

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

I've found thread of author of netty in google groups and understood that I have to change my architecture or write my own decoder as I wrote above, So, Start to think what way will be easy and better.

几味少女 2024-12-17 15:05:08

如果您无论如何都要编写自己的编解码器,您可能需要考虑为自定义数据对象实现Externalized 接口。

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

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

If you are going to write your own codecs anyway, you might want to look at implementing the Externalizable interface for custom data objects.

  • Serializable is low-effort, but worst performance (serializes everything).
  • Protobuf is a good trade-off between effort and performance (requires .proto maintenance)
  • Externalizable is high effort, but best performance (custom minimal codecs)

If you already know your project will have to scale like a mountain goat, you may have to go the hard road. Protobuf is not a silver bullet.

南冥有猫 2024-12-17 15:05:08

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

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

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

Theoretically this can be done by modifying the pipeline for each incoming message to suit the incoming message. Take a look at the port unification example in Netty.

Sequence would be:
1) In frame decoder or another "DecoderMappingDecoder" you check the message type of the incoming message
2) Modify the pipeline dynamically as shown in the example

But why not use different connections and follow this sequence:
1) Add other decoders in pipeline based on the incoming message only once.
2) Add the same instance of channel upstream handler as the last handler in the pipeline, this way all messages get routed to the same instance, which is almost like having a single connection.

信仰 2024-12-17 15:05:08

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

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

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

the problem is that there is no way to distinct two different protobuf messages from each other in binary format. But there is a way to solve it within the protobuf file:

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

optional fields that are not set produce no overhead. Additionally you can add an Enum, but it is just a bonus.

玩套路吗 2024-12-17 15:05:08

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

The issue is not quite a Netty limitation or encoder/decoder limitation. The problem is that Google Protocol Buffers are offering just a way to serialize/deserialize objects, but is not provide a protocol. They have some kind of RPC implementation as part of standard distribution, but if you'll try to implement their RPC protocol then you'll end up with 3 layers of indirection.
What I have done in one of the project, was to define a message that is basically an union of messages. This message contains one field that is Type and another field that is the actual message. You'll still end-up with 2 indirection layers, but not 3. In this way the example from Netty will work for you, but as was mention in a previous post, you have to put more logic in the business logic handler.

不羁少年 2024-12-17 15:05:08

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

You can use message tunneling to send various types of messages as payload in a single message.
Hope that helps

御弟哥哥 2024-12-17 15:05:08

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

After long research and suffering...
I came up with idea of using composition of messages into one wrapper message. Inside that message I use oneof key to limit the number of allowed objects to the only one. Checkout the example:

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
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文