国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Netty編解碼器,Netty自定義編解碼器解決粘包拆包問題,Netty編解碼器的執(zhí)行過程詳解

這篇具有很好參考價值的文章主要介紹了Netty編解碼器,Netty自定義編解碼器解決粘包拆包問題,Netty編解碼器的執(zhí)行過程詳解。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

一、編解碼器概述

1、編解碼器概述

當Netty發(fā)送或者接收一個消息的時候,就會發(fā)生一次數(shù)據(jù)轉(zhuǎn)換。入站消息會被解碼(從字節(jié)轉(zhuǎn)換為另一種格式,比如java對象);出站消息會被編碼成字節(jié)。

Netty 提供一系列實用的編解碼器,他們都實現(xiàn)了 ChannelInboundHadnler 或者 ChannelOutboundHandler 接口。在這些類中,channelRead 方法已經(jīng)被重寫了。以入站為例,對于每個從入站 Channel 讀取的消息,這個方法會被調(diào)用。隨后,它將調(diào)用由解碼器所提供的 decode()方法進行解碼,并將已經(jīng)解碼的字節(jié)轉(zhuǎn)發(fā)給 ChannelPipeline中的下一個 ChannelInboundHandler。

2、編碼器類關(guān)系圖

編碼器都繼承了MessageToByteEncoder抽象類,并且需要重寫其encode方法。
Netty編解碼器,Netty自定義編解碼器解決粘包拆包問題,Netty編解碼器的執(zhí)行過程詳解
我們發(fā)現(xiàn),編碼器繼承了ChannelOutboundHandlerAdapter,表示出站操作才會執(zhí)行。

3、解碼器類關(guān)系圖

解碼器都繼承了ByteToMessageDecoder抽象類,并且需要重寫其decode方法。
Netty編解碼器,Netty自定義編解碼器解決粘包拆包問題,Netty編解碼器的執(zhí)行過程詳解
我們發(fā)現(xiàn),解碼器繼承了ChannelInboundHandlerAdapter,表示入站操作才會執(zhí)行。

二、以編解碼器為例理解入站出站

1、Server端


import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class MyServer {
    public static void main(String[] args) throws Exception{

        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {

            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup,workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                            @Override
                            protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();//一會下斷點

                            //入站的handler進行解碼 MyByteToLongDecoder
                            pipeline.addLast(new MyByteToLongDecoder());
                            //出站的handler進行編碼
                            pipeline.addLast(new MyLongToByteEncoder());
                            //自定義的handler 處理業(yè)務(wù)邏輯
                            pipeline.addLast(new MyServerHandler());
                            System.out.println("end");
                        }
            }); //自定義初始化pipeline

            ChannelFuture channelFuture = serverBootstrap.bind(7000).sync();
            channelFuture.channel().closeFuture().sync();

        }finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}



import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

public class MyServerHandler extends SimpleChannelInboundHandler<Long> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Long msg) throws Exception {

        System.out.println("從客戶端" + ctx.channel().remoteAddress() + " 讀取到long " + msg);
        //給客戶端發(fā)送一個long
        ctx.writeAndFlush(98765L);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

2、Client端


import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

public class MyClient {
    public static void main(String[] args)  throws  Exception{

        EventLoopGroup group = new NioEventLoopGroup();

        try {

            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group).channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {

                            ChannelPipeline pipeline = ch.pipeline();

                            //加入一個出站的handler 對數(shù)據(jù)進行一個編碼
                            pipeline.addLast(new MyLongToByteEncoder());

                            //這時一個入站的解碼器(入站handler )
                            pipeline.addLast(new MyByteToLongDecoder());
                            //加入一個自定義的handler , 處理業(yè)務(wù)
                            pipeline.addLast(new MyClientHandler());

                        }
            }); //自定義一個初始化類

            ChannelFuture channelFuture = bootstrap.connect("localhost", 7000).sync();

            channelFuture.channel().closeFuture().sync();

        }finally {
            group.shutdownGracefully();
        }
    }
}


import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

public class MyClientHandler  extends SimpleChannelInboundHandler<Long> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Long msg) throws Exception {

        System.out.println("服務(wù)器的ip=" + ctx.channel().remoteAddress());
        System.out.println("收到服務(wù)器消息=" + msg);

    }

    //重寫channelActive 發(fā)送數(shù)據(jù)
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("MyClientHandler 發(fā)送數(shù)據(jù)");
        ctx.writeAndFlush(123456L); //發(fā)送的是一個long
    }
}

3、編解碼器


import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;

public class MyLongToByteEncoder extends MessageToByteEncoder<Long> {
    //編碼方法
    @Override
    protected void encode(ChannelHandlerContext ctx, Long msg, ByteBuf out) throws Exception {

        System.out.println("MyLongToByteEncoder encode 被調(diào)用");
        System.out.println("msg=" + msg);
        out.writeLong(msg);

    }
}


import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.util.List;

public class MyByteToLongDecoder extends ByteToMessageDecoder {
    /**
     *
     * decode方法 會根據(jù)接收的數(shù)據(jù),被調(diào)用多次, 直到確定沒有新的元素被添加到list
     * , 或者是ByteBuf 沒有更多的可讀字節(jié)為止
     * 如果list out 不為空,就會將list的內(nèi)容傳遞給下一個 channelinboundhandler處理, 該處理器的方法也會被調(diào)用多次
     *
     * @param ctx 上下文對象
     * @param in 入站的 ByteBuf
     * @param out List 集合,將解碼后的數(shù)據(jù)傳給下一個handler
     * @throws Exception
     */
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {

        System.out.println("MyByteToLongDecoder 被調(diào)用");
        //因為 long 8個字節(jié), 需要判斷有8個字節(jié),才能讀取一個long
        if(in.readableBytes() >= 8) {
            out.add(in.readLong());
        }
    }
}

3、執(zhí)行查看結(jié)果

client端:

MyClientHandler 發(fā)送數(shù)據(jù)
MyLongToByteEncoder encode 被調(diào)用
msg=123456
MyByteToLongDecoder 被調(diào)用
服務(wù)器的ip=localhost/127.0.0.1:7000
收到服務(wù)器消息=98765

server端:

MyByteToLongDecoder 被調(diào)用
從客戶端/127.0.0.1:58478 讀取到long 123456
MyLongToByteEncoder encode 被調(diào)用
msg=98765

根據(jù)我們的執(zhí)行結(jié)果,我們可以簡單的得出一個結(jié)論,執(zhí)行流程大致是這樣的:

Netty編解碼器,Netty自定義編解碼器解決粘包拆包問題,Netty編解碼器的執(zhí)行過程詳解

4、注意事項

編解碼器只能處理指定類型的數(shù)據(jù),如果數(shù)據(jù)類型不匹配,會跳過編解碼,但是數(shù)據(jù)不會丟失。

比如說客戶端ctx.writeAndFlush(Unpooled.copiedBuffer(“abcdabcdabcdabcd”,CharsetUtil.UTF_8)); 發(fā)送一個16位的字符串,Encoder的encode方法雖然會執(zhí)行,但是并不會編碼。因此我們編寫 Encoder 是要注意傳入的數(shù)據(jù)類型和處理的數(shù)據(jù)類型一致。

我們看一下MessageToByteEncoder的write方法:

// io.netty.handler.codec.MessageToByteEncoder#write
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
    ByteBuf buf = null;
    try {
        if (acceptOutboundMessage(msg)) {//判斷當前msg 是不是應(yīng)該處理的類型,如果是就處理,不是就跳過encode
            @SuppressWarnings("unchecked")
            I cast = (I) msg;
            buf = allocateBuffer(ctx, cast, preferDirect);
            try {
                encode(ctx, cast, buf);
            } finally {
                ReferenceCountUtil.release(cast);
            }

            if (buf.isReadable()) {
                ctx.write(buf, promise);
            } else {
                buf.release();
                ctx.write(Unpooled.EMPTY_BUFFER, promise);
            }
            buf = null;
        } else {
            ctx.write(msg, promise);
        }
    } catch (EncoderException e) {
        throw e;
    } catch (Throwable e) {
        throw new EncoderException(e);
    } finally {
        if (buf != null) {
            buf.release();
        }
    }
}

三、Netty其他內(nèi)置編解碼器

Netty內(nèi)含許多編解碼器,通常來說足夠應(yīng)對我們?nèi)粘9ぷ髁耍?/p>

1、ReplayingDecoder

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ReplayingDecoder;

import java.util.List;

public class MyByteToLongDecoder extends ReplayingDecoder<Void> {
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {

        System.out.println("MyByteToLongDecoder2 被調(diào)用");
        //在 ReplayingDecoder 不需要判斷數(shù)據(jù)是否足夠讀取,內(nèi)部會進行處理判斷
        out.add(in.readLong());
    }
}

ReplayingDecoder 使用方便,但它也有一些局限性:
1、并不是所有的 ByteBuf操作都被支持,如果調(diào)用了一個不被支持的方法,將會拋出一個UnsupportedOperationException。
2、ReplayingDecoder 在某些情況下可能稍慢于 ByteToMessageDecoder,例如網(wǎng)絡(luò)緩慢并且消息格式復(fù)雜時,消息會被拆成了多個碎片,速度變慢。

2、其他編碼器

LineBasedFrameDecoder:這個類在 Netty 內(nèi)部也有使用,它使用行尾控制字符 (\n 或者\r\n)作為分隔符來解析數(shù)據(jù)。
DelimiterBasedFrameDecoder: 使用自定義的特殊字符作為消息的分隔符。
HttpObiectDecoder: 一個 HTTP 數(shù)據(jù)的解碼器。
LengthFieldBasedFrameDecoder: 通過指定長度來標識整包消息,這樣就可以自動的處理黏包和半包消息。

編碼器與解碼器都是成對出現(xiàn)的。

3、內(nèi)置編解碼器處理粘包拆包問題

Netty解決粘包和拆包問題的四種方案

四、自定義編解碼器實現(xiàn)粘包拆包問題

Netty解決粘包拆包問題,Netty使用自定義編解碼器解決粘包拆包問題文章來源地址http://www.zghlxwxcb.cn/news/detail-422002.html

到了這里,關(guān)于Netty編解碼器,Netty自定義編解碼器解決粘包拆包問題,Netty編解碼器的執(zhí)行過程詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 23.Netty源碼之內(nèi)置解碼器

    在前兩節(jié)課我們介紹了 TCP 拆包/粘包的問題,以及如何使用 Netty 實現(xiàn)自定義協(xié)議的編解碼??梢钥吹?,網(wǎng)絡(luò)通信的底層實現(xiàn),Netty 都已經(jīng)幫我們封裝好了,我們只需要擴展 ChannelHandler 實現(xiàn)自定義的編解碼邏輯即可。 更加人性化的是,Netty 提供了很多開箱即用的解碼器,這些

    2024年02月13日
    瀏覽(27)
  • 「 計算機網(wǎng)絡(luò) 」TCP的粘包拆包問題

    「 計算機網(wǎng)絡(luò) 」TCP的粘包拆包問題

    參考鳴謝 大病初愈,一分鐘看懂TCP粘包拆包 雷小帥 TCP 的粘包拆包以及解決方案 一樂說 當我們在進行網(wǎng)絡(luò)傳輸時,由于各種原因,數(shù)據(jù)包的發(fā)送和接收可能會出現(xiàn)粘包和拆包的問題。粘包和拆包都是數(shù)據(jù)分組錯誤的情況,其中粘包指的是多個數(shù)據(jù)包被合并成一個,而拆包則

    2024年02月01日
    瀏覽(25)
  • 【計網(wǎng)】一起聊聊TCP的粘包拆包問題吧

    【計網(wǎng)】一起聊聊TCP的粘包拆包問題吧

    在TCP中,粘包和拆包問題是十分常見的,如 基于TCP協(xié)議 的RPC框架、Netty等。 粘包(Packet Stickiness) 指的是在網(wǎng)絡(luò)通信中,發(fā)送方連續(xù)發(fā)送的多個小數(shù)據(jù)包被接收方一次性接收的現(xiàn)象。這可能是因為底層傳輸層協(xié)議(如TCP)會將 多個小數(shù)據(jù)包合并成一個大的數(shù)據(jù)塊 進行傳輸,導(dǎo)

    2024年04月12日
    瀏覽(16)
  • Netty自定義應(yīng)用層協(xié)議逃不開的粘包和拆包處理

    Netty自定義應(yīng)用層協(xié)議逃不開的粘包和拆包處理

    導(dǎo)致一次發(fā)送的數(shù)據(jù)被分成多個數(shù)據(jù)包進行傳輸,或者多次發(fā)送的數(shù)據(jù)被粘成一個數(shù)據(jù)包進行傳輸 使用TCP進行數(shù)據(jù)傳輸時,TCP是一種有序的字節(jié)流,其中是一個一個的數(shù)據(jù)報文發(fā)送到系統(tǒng)的緩沖區(qū)中。因此在發(fā)送端和接收端之間無法保證數(shù)據(jù)的分割和邊界。這就可能導(dǎo)致數(shù)據(jù)

    2023年04月23日
    瀏覽(31)
  • Android 大圖顯示優(yōu)化方案-加載Gif 自定義解碼器

    Android 大圖顯示優(yōu)化方案-加載Gif 自定義解碼器

    基于Glide做了圖片顯示的優(yōu)化,尤其是加載Gif圖的優(yōu)化,原生Glide加載Gif圖性能較低。在原生基礎(chǔ)上做了自定義解碼器的優(yōu)化,提升Glide性能 Glide加載大圖和Gif 尤其是列表存在gif時,會有明顯卡頓,cpu和內(nèi)存占用較高, Glide的優(yōu)勢 就是有一套圖片生命周期的維護,但是加載g

    2024年02月09日
    瀏覽(24)
  • SpringBoot項目整合OpenFeign、實現(xiàn)動態(tài)IP+URL請求、自定義(編碼器\解碼器)

    OpenFeign 是Spring Cloud在Feign的基礎(chǔ)上支持了SpringMVC的注解,如@RequestMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通過動態(tài)代理的方式產(chǎn)生實現(xiàn)類,實現(xiàn)類中. 啟動類加上注解: @EnableDiscoveryClient 動態(tài)URL 工具類: FeignUtils.class

    2024年02月02日
    瀏覽(28)
  • Unity-TCP-網(wǎng)絡(luò)聊天功能(一):?API、客戶端服務(wù)器、數(shù)據(jù)格式、粘包拆包

    Unity-TCP-網(wǎng)絡(luò)聊天功能(一):?API、客戶端服務(wù)器、數(shù)據(jù)格式、粘包拆包

    TCP是面向連接的。因此需要創(chuàng)建監(jiān)聽器,監(jiān)聽客戶端的連接。當連接成功后,會返回一個TcpClient對象。通過TcpClient可以接收和發(fā)送數(shù)據(jù)。 VS創(chuàng)建C# .net控制臺應(yīng)用 項目中創(chuàng)建文件夾Net,Net 下添加TCPServer.cs類,用來創(chuàng)建TCPListener和Accept客戶端連接,實例化一個TCPServcer放在Main函數(shù)

    2024年02月07日
    瀏覽(129)
  • Netty粘包與拆包

    文章首發(fā)地址 TCP是一個“流”協(xié)議。所謂流,就是沒有界限的一長串二進制數(shù)據(jù)。 拆包和粘包 :TCP作為傳輸層協(xié)議,并不了解上層業(yè)務(wù)數(shù)據(jù)的具體含義,它會根據(jù)TCP緩沖區(qū)的實際情況進行數(shù)據(jù)包的劃分,所以在業(yè)務(wù)上認為是一個完整包的,可能會被TCP拆分成多個包進行發(fā)送

    2024年02月16日
    瀏覽(38)
  • 【Python編程錯誤:‘utf-8‘編解碼器無法解碼字節(jié)0xd5】--解決方法詳解

    【Python編程錯誤:\\\'utf-8’編解碼器無法解碼字節(jié)0xd5】–解決方法詳解 Python是一門非常流行的高級編程語言,用戶可以很方便地使用它來實現(xiàn)各種功能。然而,在使用Python編寫代碼時,有時會遇到各種錯誤。本文將詳細介紹一種常見的Python編程錯誤——\\\'utf-8’編解碼器無法解

    2024年02月08日
    瀏覽(23)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包