java - 为什么我在我的 netty 管道解码期间恰好丢失了 5 个字节?

标签 java netty

我正在为能够传输文件和结构化消息的协议(protocol)编写 netty 管道。文件传输通过结构化消息(握手)启动,后跟代表文件的字节流。

传入文件的确切消息流如下所示(服务器是我的 netty 实现,客户端是另一个软件):

            +---------+                                    +---------+
            | Client  |                                    | Server  |
            +---------+                                    +---------+
                 |                                              |
                 | Connect (1)                                  |
                 |--------------------------------------------->|
                 |                                              |
                 | Handshake to announce incoming file (2)      |
                 |--------------------------------------------->|
                 |                                              |
                 |                Acknowledge file transfer (3) |
                 |<---------------------------------------------|
                 |                                              |
                 | Send file (4)                                |
                 |--------------------------------------------->|

协议(protocol)消息如下所示:

            +---------+----------------+----------------+
            | Length  |      Type      | Actual Message |
            | 4 bytes |     1 byte     |   N bytes      |
            +---------+----------------+----------------+

在握手消息的情况下,Actual Message 仅包含一个 Long 值,token

这是 ReplayingDecoder:

    public class ProtocolDecoder extends ReplayingDecoder<State> {

      private Integer msgType;
      private Long token;


      public enum State {
        LENGTH,
        MSG_TYPE,
        TOKEN
      }

      public ProtocolDecoder() {
        super(State.LENGTH);
      }

      @Override
      protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {

        switch (state()) {

          case LENGTH:
            // (2) read the message length from the handshake
            long messageLength = in.readUnsignedIntLE();
            checkpoint(State.MSG_TYPE);

          case MSG_TYPE:
            // (2) read the message type from the handshake
            msgType = in.readBoolean();
            checkpoint(State.TOKEN);

          case TOKEN:
            try {
              // (2) read the token from the handshake
              token = in.readUnsignedIntLE();
              // (3) write back the acknowledgement
              ctx.channel().writeAndFlush(new Acknowledgement(token));
              // (4) done reading the protocol message
              // now switch to the file protocol
              ctx.pipeline().addLast(new FileInboundHandler());
              // write everything that is still in the buffer to the
              // modified pipeline
              ByteBuf rest = in.readBytes(super.actualReadableBytes());
              out.add(rest);
              // remove the protocol handshake decoder and pass
              // the rest of this channel to the `FileInboundHandler`
              ctx.pipeline().remove(this);
            } finally {
              reset();
            }
            break;
          default:
            throw new Error("Shouldn't reach here.");
        }
      }

      private void reset() {
        token = null;
        msgType = null;
      }

FileInboundHandler 只是创建一个文件并将所有 ByteBuf 写入其中。

这在原则上是可行的,唯一的问题是每个文件在开头恰好错过了 5 个字节。

我有两个问题:

1) 如果我将 LoggingHandler 作为管道中的第一个处理程序,我能否确保记录套接字上的所有流量,无论我的解码器是否有问题?

2) 当调用 ctx.channel().writeAndFlush() 时,它是否只刷新“出站”缓冲区,这意味着我可以确定我没有刷新任何我没有消耗的字节来自入站缓冲区了吗?

最佳答案

会不会是您忘记在每个 switch case 的语句末尾放置一个 break;?现在来看,从第一个 LENGTH 读取开始,它会下降到类型和 token 读取,获得 5 个字节太多: boolean 值(一个字节)和 token (读取为 unsigned int,4字节)。

关于java - 为什么我在我的 netty 管道解码期间恰好丢失了 5 个字节?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43518543/

相关文章:

java - Selenium 无法在 Iframe 中找到元素,即使它们可见

java - 通过 HttpClient 接受所有 Cookie

java - 获取大量 `PrematureCloseException : Connection prematurely closed BEFORE response`

java - 为什么需要处理消息的分片

Java异常: java. lang.ClassCastException : javax. swing.Timer无法转换为javax.swing.JButton

java - Jersey 客户端发送 application/json 类型的字符串

java - 如何使用 spring-mvc 访问 mysql 中的特定表

java - 如何使用 JDBC 来最大化 Netty 的性能?

java - Netty4 添加 HttpChunkAggregator

java - servlet 容器中基于 Netty 的服务器