18 FixedLengthFrameDecoder

定長(zhǎng)協(xié)議

1 FixedLengthFrameDecoder簡(jiǎn)介

FixedLengthFrameDecoder采用的是定長(zhǎng)協(xié)議:即把固定的長(zhǎng)度的字節(jié)數(shù)當(dāng)做一個(gè)完整的消息

例如,我們規(guī)定每3個(gè)字節(jié),表示一個(gè)有效報(bào)文,如果我們分4次總共發(fā)送以下9個(gè)字節(jié):

   +---+----+------+----+
   | A | BC | DEFG | HI |
   +---+----+------+----+

那么通過(guò)FixedLengthFrameDecoder解碼后,實(shí)際上只會(huì)解析出來(lái)3個(gè)有效報(bào)文

   +-----+-----+-----+
   | ABC | DEF | GHI |
   +-----+-----+-----+

FixedLengthFrameDecodert提供了以下構(gòu)造方法

public FixedLengthFrameDecoder(int frameLength) {
    if (frameLength <= 0) {
        throw new IllegalArgumentException(
                "frameLength must be a positive integer: " + frameLength);
    }
    this.frameLength = frameLength;
}

其中:frameLength就是我們指定的長(zhǎng)度。

需要注意的是FixedLengthFrameDecoder并沒(méi)有提供一個(gè)對(duì)應(yīng)的編碼器,因?yàn)榻邮辗街恍枰鶕?jù)字節(jié)數(shù)進(jìn)行判斷即可,發(fā)送方無(wú)需編碼

2 FixedLengthFrameDecoder使用案例

server端:FixedLengthFrameDecoderServer

public class FixedLengthFrameDecoderServer {
    public static void main(String[] args) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap(); // (2)
            b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) // (3)
                    .childHandler(new ChannelInitializer<SocketChannel>() { // (4)
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new FixedLengthFrameDecoder(3));
                            // 自定義這個(gè)ChannelInboundHandler打印拆包后的結(jié)果
                            ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
                                @Override
                                public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                    if (msg instanceof ByteBuf) {
                                        ByteBuf packet = (ByteBuf) msg;
                                        System.out.println(
                                                new Date().toLocaleString() + ":" + packet.toString(Charset.defaultCharset()));
                                    }
                                }
                            });
                        }
                    });
            // Bind and start to accept incoming connections.
            ChannelFuture f = b.bind(8080).sync(); // (7)
            System.out.println("FixedLengthFrameDecoderServer Started on 8080...");
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
}

Client端:FixedLengthFrameDecoderClient

public class FixedLengthFrameDecoderClient {
   public static void main(String[] args) throws Exception {
      EventLoopGroup workerGroup = new NioEventLoopGroup();
      try {
         Bootstrap b = new Bootstrap(); // (1)
         b.group(workerGroup); // (2)
         b.channel(NioSocketChannel.class); // (3)
         b.option(ChannelOption.SO_KEEPALIVE, true); // (4)
         b.handler(new ChannelInitializer<SocketChannel>() {
            @Override
            public void initChannel(SocketChannel ch) throws Exception {
               ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
                   //在于server建立連接后,即發(fā)送請(qǐng)求報(bào)文
                  public void channelActive(ChannelHandlerContext ctx) {
                     ByteBuf A = Unpooled.buffer().writeBytes("A".getBytes());
                     ByteBuf BC = Unpooled.buffer().writeBytes("BC".getBytes());
                     ByteBuf DEFG = Unpooled.buffer().writeBytes("DEFG".getBytes());
                     ByteBuf HI = Unpooled.buffer().writeBytes("HI".getBytes());
                     ctx.writeAndFlush(A);
                     ctx.writeAndFlush(BC);
                     ctx.writeAndFlush(DEFG);
                     ctx.writeAndFlush(HI);
                    }
               });
            }
         });
         // Start the client.
         ChannelFuture f = b.connect("127.0.0.1",8080).sync(); // (5)
         // Wait until the connection is closed.
         f.channel().closeFuture().sync();
      } finally {
         workerGroup.shutdownGracefully();
      }
   }
}

先后運(yùn)行server端與client端后,server端控制臺(tái)輸出

LineBasedFrameDecoderServer Started on 8080...
2018-9-8 15:20:20:ABC
2018-9-8 15:20:20:DEF
2018-9-8 15:20:20:GHI

可以看到FixedLengthFrameDecoder的確將請(qǐng)求的數(shù)據(jù),按照每3個(gè)字節(jié)當(dāng)做一個(gè)完整的請(qǐng)求報(bào)文。

通常情況下,很少有client與server交互時(shí),直接使用定長(zhǎng)協(xié)議,可能會(huì)造成浪費(fèi)。例如你實(shí)際要發(fā)送的實(shí)際只有3個(gè)字節(jié),但是定長(zhǎng)協(xié)議設(shè)置的1024,那么可能你就要為這3個(gè)字節(jié)基礎(chǔ)上,在加1021個(gè)空格,以便server端可以解析這個(gè)請(qǐng)求。在下一節(jié)我們將要介紹的LengthFieldBasedFrameDecoder,支持動(dòng)態(tài)指定報(bào)文的長(zhǎng)度。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1、TCP為什么需要3次握手,4次斷開(kāi)? “三次握手”的目的是“為了防止已失效的連接請(qǐng)求報(bào)文段突然又傳送到了服務(wù)端...
    杰倫哎呦哎呦閱讀 3,663評(píng)論 0 6
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,688評(píng)論 19 139
  • 博主最近在復(fù)習(xí)HTTP,之前用書(shū)主要是《計(jì)算機(jī)網(wǎng)絡(luò)》謝希仁版本,最近結(jié)合網(wǎng)上博客,進(jìn)行復(fù)習(xí)和提綱式的總結(jié)。 一、概...
    stoneyang94閱讀 4,290評(píng)論 1 8
  • 地有花草,草變?cè)?,不及花絲芬芳,人看花嬌寵,棄草于腳底,草之迷戀于花,護(hù)花也。旁有枯樹(shù)林一片,花草冷笑之...
    石Hyacinth閱讀 809評(píng)論 0 0
  • 玻璃窗外 馬路上的車多了起來(lái) 路上的行人也多了起來(lái) 手提箱滾滾的 大背包也多了起來(lái) 連人心似乎也鼓脹了起來(lái) 年是什...
    林有朽木閱讀 198評(píng)論 5 9

友情鏈接更多精彩內(nèi)容