为什么我在netty管道中解码时会丢失5个字节?

时间:2017-04-20 11:41:01

标签: java netty

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

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

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

协议消息如下所示:

            +---------+----------------+----------------+
            | 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()时,它是否仅冲洗&#34;出站&#34;缓冲区,这意味着我可以确定我没有刷新我从入站缓冲区中消耗的任何字节吗?

1 个答案:

答案 0 :(得分:1)

您是否忘记在每个交换机案例的语句末尾添加break;?现在看一下,从第一个LENGTH读取它将会落入类型和令牌读取,得到5个字节太多:布尔值(一个字节)和令牌(读取为unsigned int, 4个字节)。