【问题标题】:Encoding and Decoding multiple different types with Netty 5使用 Netty 5 编码和解码多种不同类型
【发布时间】:2014-04-29 23:28:08
【问题描述】:

我正在尝试实现具有多种不同数据包类型的网络协议。我面临的问题是用 Netty 实现这个的最“正确”的方式。我会先发布一些课程,然后描述我想要完成的任务。

public class ItemStack {

    public ItemStack(final int item, final int amount) {
        if (item < 0) {
            throw new IllegalArgumentException("item must be non-negative integer: " + item);
        }
        if (amount < 1) {
            throw new IllegalArgumentException("amount must be positive integer: " + amount);
        }
        this.item = item;
        this.amount = amount;
    }

    public int getItem() {
        return item;
    }

    public int getAmount() {
        return amount;
    }

    private final int item;
    private final int amount;
}
public class ChatMessage {

    public ChatMessage(final String playerName, final String message) {
        if (playerName == null) {
            throw new IllegalArgumentException("playerName must not be null");
        }
        if (message == null) {
            throw new IllegalArgumentException("message must not be null");
        }
        this.playerName = playerName;
        this.message = message;
    }

    public String getPlayerName() {
        return playerName;
    }

    public String getMessage() {
        return message;
    }

    private final int playerName;
    private final int message;
}

现在,所有通过网络传输的 POJO 都将具有一个数据包标识符。这将是一个 1 字节的代码,它将让解码器知道它是什么类型的数据包,以及如何解码它。

处理这种情况最合适的方法是什么?拥有一个扩展 ByteToMessageDecoder 的 PacketDecoder 类会更好(阅读更传统),该类读取一个字节,确定类型,然后在同一个类中,使用适当的方法解码数据包,如下所示:

public class PacketDecoder extends ByteToMessageDecoder {

    protected void decode(
        final ChannelHandlerContext context, final ByteBuf buf, List<Object> objects) throws Exception {
        if (buf.readableBytes < 1) {
            return;
        }
        final int opcode = buf.readByte() & 0xff;
        final Packet packet = decodePacket(opcode);
        objects.add(packet);
    }

    private Packet decodePacket(final int opcode, final ByteBuf buf) {
        if (buf == null) {
            throw new IllegalArgumentException("buf must not be null");
        }
        Packet packet = null;
        switch (opcode) {
            case 0:
                packet = decodeItemStack(buf);
                break;

            case 1:
                packet = decodeChatMessage(buf);
                break;
            // ...
        }
        return packet;
    }
}

或者将每种类型的解码器都添加到管道中会更好吗?

【问题讨论】:

    标签: java networking netty


    【解决方案1】:

    我在自己的程序中执行此操作,并且使用了单个解码器,因为这样做更直接。我可以看到想要多个解码器的唯一原因是如果需要扩展或动态更改您的服务器理解的协议。例如,您的服务器的某些方面可能是免费的,而其他方面则需​​要为许可密钥打开的扩展付费,那么我可以看到这种架构很重要。或者您可能会动态加载协议的扩展。我认为你需要一个真正的理由来将解码分割成几个解码器,除了它在架构上是纯粹的。

    在这种情况下,您可以将多个解码器添加到管道中,但每个解码器都需要播放好并将不适合它的数据包转发到管道中的下一个解码器。您还必须小心不要从下游解码器可能需要的字节中提取字节。

    这是我不会做的。每个消息架构的解码器。这将是繁琐的编写和维护。由于编写每个解码器来播放良好和转发数据包都会产生开销,因此我不会在每次编写解码器时都进行该练习。你可以通过一个很好的基类来扩展这个问题,但是当你可以解析第一个字节并做一个简单的 if 阶梯时,为什么还要经历所有这些麻烦呢?

    【讨论】:

    • 这也是我的想法。我想到的另一个问题是,如果在数据包的解码过程中,缓冲区用完了可读字节,会发生什么?是否有一些机制可以让我在实际数据之前附加发送的数据的总大小?例如,如果我有一个包含两个字符串的数据包。当前字符串长度在字符串数据之前写入。 [string_length][string_data] 但是如果长度是可读的会发生什么,你将它与剩下的可读字节的数量进行比较,实际上剩下的可读字节更少了?
    • 我使用 FrameDecoder 作为我的基类,以确保我可以在开始解析消息之前完全处理它。 docs.jboss.org/netty/3.1/api/org/jboss/netty/handler/codec/…
    猜你喜欢
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-28
    • 2018-04-12
    • 2020-04-09
    • 2015-05-08
    相关资源
    最近更新 更多