最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Netty之使用DelimiterBasedFrameDecoder進行消息分隔詳解

 更新時間:2023年12月14日 09:59:00   作者:Terisadeng  
這篇文章主要介紹了Netty之使用DelimiterBasedFrameDecoder進行消息分隔詳解,在使用Netty進行TCP消息傳輸時,為了上層協(xié)議能夠?qū)ο⒄_區(qū)分,避免粘包和拆包導致的問題,一般可以通過消息定長、將回車換行符作為消息結(jié)束符,需要的朋友可以參考下

DelimiterBasedFrameDecoder消息分隔

在使用Netty進行TCP消息傳輸時,為了上層協(xié)議能夠?qū)ο⒄_區(qū)分,避免粘包和拆包導致的問題。

一般可以通過消息定長、將回車換行符作為消息結(jié)束符、將特殊的分隔符作為消息的結(jié)束標志或者在消息頭中定義長度字段來標識消息的總長度。

其中常用的通過分隔符作為消息的結(jié)束標志就涉及到Netty的DelimiterBasedFrameDecoder類,服務端如下:

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
public class EchoServer
{
    public void bind(int port)throws Exception{
        //配置服務端的NIO線程組
        EventLoopGroup bossGroup=new NioEventLoopGroup();
        EventLoopGroup workerGroup=new NioEventLoopGroup();
        try
        {
            ServerBootstrap b=new ServerBootstrap();
            b.group(bossGroup, workerGroup)
            .channel(NioServerSocketChannel.class)
            .option(ChannelOption.SO_BACKLOG, 1024)
            //控制臺輸出服務端運行日志
            .handler(new LoggingHandler(LogLevel.INFO))
            //編寫服務端接收和發(fā)送消息的具體邏輯
            .childHandler(new ChildChannleHandler());
            //綁定啟動端口,同步等待成功
            ChannelFuture f=b.bind(port).sync();
            //等待服務端監(jiān)聽端口關(guān)閉
            f.channel().closeFuture().sync();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        finally{
            //釋放線程資源
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
    //服務端接收到客戶端的消息時會先執(zhí)行該類的initChannel()方法進行channel的初始化操作
    private class ChildChannleHandler extends ChannelInitializer<SocketChannel>{
        @Override
        protected void initChannel(SocketChannel arg0)
            throws Exception
        {
            //創(chuàng)建分隔符緩沖對象,使用"$_"作為分隔符
            ByteBuf delimiter=Unpooled.copiedBuffer("$_".getBytes());
            //創(chuàng)建DelimiterBasedFrameDecoder對象,將其加入到ChannelPipeline
            //參數(shù)1024表示單條消息的最大長度,當達到該長度仍然沒有找到分隔符就拋出TooLongFrame異常,第二個參數(shù)就是分隔符
            //由于DelimiterBasedFrameDecoder自動對請求消息進行了解碼,下面的ChannelHandler接收到的msg對象就是完整的消息包
            arg0.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, delimiter));
            //StringDecoder解碼器將ByteBuf解碼成字符串對象,這樣在ChannelHandlerAdapter中讀取消息時就不需要通過ByteBuf獲取了
            arg0.pipeline().addLast(new StringDecoder());
            //對網(wǎng)絡事件進行讀寫操作的類
            arg0.pipeline().addLast(new EchoServerHandler());
        }
    }
    public static void main(String[] args)throws Exception
    {
        int port =8888;
        if (args!=null&&args.length>0)
        {
            port=Integer.valueOf(args[0]);
        }
        new EchoServer().bind(port);
    }
}

服務端消息讀寫操作:

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
//網(wǎng)絡I/O事件讀寫操作
public class EchoServerHandler extends ChannelHandlerAdapter
{
    int counter=0;
    //接收客戶端發(fā)送的消息并返回響應
    @Override
    public void channelRead(ChannelHandlerContext ctx,Object msg)throws Exception{
        //獲取String類型的請求消息(StringDecoder已經(jīng)對消息進行解碼)
        String body=(String)msg;
        System.out.println("This is "+ ++counter+"times receive client : ["+body+"]");
        //由于設(shè)置了DelimiterBasedFrameDecoder過濾掉了分隔符"$_",   因此需要將返回消息尾部拼接上分隔符
        body+="$_";
        //將接收到的消息再放到ByteBuf中重新發(fā)送給客戶端
        ByteBuf buf=Unpooled.copiedBuffer(body.getBytes());
        //把待發(fā)送的消息放到發(fā)送緩沖數(shù)組中,并把緩沖區(qū)中的消息全部寫入SockChannel發(fā)送給客戶端
        ctx.writeAndFlush(buf);
    }
    //發(fā)生異常時關(guān)閉ChannelHandlerContext,釋放和ChannelHandlerContext相關(guān)聯(lián)的句柄等資源
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx,Throwable cause){
        cause.printStackTrace();
        ctx.close();
    }
}

客戶端:

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
//客戶端
public class EchoClient
{
    public void connect(int port,String host)throws Exception{
        //創(chuàng)建客戶端進行I/O讀寫的線程組
        EventLoopGroup g=new NioEventLoopGroup();
        try
        {
            //創(chuàng)建客戶端啟動輔助類Bootstrap
            Bootstrap b=new Bootstrap();
            b.group(g)
            //設(shè)置Channel
            .channel(NioSocketChannel.class)
            //配置Channel
            .option(ChannelOption.TCP_NODELAY, true)
            //添加處理類,這里為了方便直接使用了匿名內(nèi)部類
            .handler(new ChannelInitializer<SocketChannel>()
            {
                //當創(chuàng)建NioSocketChannel成功后,將ChannelHandler設(shè)置到ChannelPipeline中處理網(wǎng)絡I/O事件
                @Override
                protected void initChannel(SocketChannel arg0)
                    throws Exception
                {
                    //與服務端相同,需要配置一系列的ChannelHandler
                    ByteBuf delimiter=Unpooled.copiedBuffer("$_".getBytes());
                    arg0.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,delimiter));
                    arg0.pipeline().addLast(new StringDecoder());
                    //客戶端的處理類加入ChannelPipeline
                    arg0.pipeline().addLast(new EchoClientHandler());
                }
            });
            //調(diào)用connect方法發(fā)起異步連接,并調(diào)用同步方法等待連接成功
            ChannelFuture f=b.connect(host, port).sync();
            //f.channel().writeAndFlush(Unpooled.wrappedBuffer("111$_".getBytes()));
            //等待客戶端連接關(guān)閉
            f.channel().closeFuture().sync();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        finally{
            //釋放線程組
            g.shutdownGracefully();
        }
    }
    public static void main(String[] args)throws Exception
    {
        int port=8888;
        if (args!=null&&args.length>0)
        {
            port=Integer.valueOf(args[0]);
        }
        new EchoClient().connect(port, "127.0.0.1");
    }
}

客戶端網(wǎng)絡I/O事件處理:

import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
//客戶端讀寫網(wǎng)絡I/O事件類
public class EchoClientHandler extends ChannelHandlerAdapter
{
    int counter;
    //發(fā)送到服務端的消息,注意結(jié)尾的分隔符一定要和服務端配置的分隔符一致,否則服務端ChannelInitializer.initChannel()方法雖然能夠調(diào)用,但是DelimiterBasedFrameDecoder無法找到分隔符,不會調(diào)用讀取消息的channelRead方法
    static final String ECHO_REQ="Hi,Welcome to Netty.$_";
    public EchoClientHandler(){
    }
    //客戶端發(fā)送消息的方法
    @Override
    public void channelActive(ChannelHandlerContext ctx)throws Exception{
        for (int i = 0; i < 10; i++ )
        {
            //Unpooled.copiedBuffer()方法是深克隆,也可以使用Unpooled.buffer()寫入消息發(fā)送
            ctx.writeAndFlush(Unpooled.copiedBuffer(ECHO_REQ.getBytes()));
        }
    }
    //讀取服務端發(fā)送的消息
    @Override
    public void channelRead(ChannelHandlerContext ctx,Object msg)throws Exception{
        String body=(String)msg;
        System.out.println("This is "+ ++counter+" times receive server:["+body+"]");
    }
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx)throws Exception{
        //將消息發(fā)送隊列中的消息寫入到SocketChannel中發(fā)送給對方,channelActive使用了writeAndFlush這里可以不重寫
        ctx.flush();
    }
    //異常處理,關(guān)閉ChannelHandlerContext
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx,Throwable cause){
        cause.printStackTrace();
        ctx.close();
    }
}

啟動服務端:

啟動客戶端發(fā)送消息:

到此這篇關(guān)于Netty之使用DelimiterBasedFrameDecoder進行消息分隔詳解的文章就介紹到這了,更多相關(guān)DelimiterBasedFrameDecoder進行消息分隔內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • MyBatis框架底層的執(zhí)行原理源碼解析

    MyBatis框架底層的執(zhí)行原理源碼解析

    這篇文章主要介紹了MyBatis框架底層的執(zhí)行原理源碼解析,本文通過圖文實例代碼相結(jié)合給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-06-06
  • 幾種常見的Java運行時異常小結(jié)

    幾種常見的Java運行時異常小結(jié)

    在Java編程語言中異常處理是一項關(guān)鍵的機制,它幫助開發(fā)者識別和修復程序運行時可能出現(xiàn)的問題,下面這篇文章主要給大家介紹了幾種常見的Java運行時異常的相關(guān)資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-08-08
  • Java?AQS?原理與?ReentrantLock?實現(xiàn)方法

    Java?AQS?原理與?ReentrantLock?實現(xiàn)方法

    AQS 的作用是解決同步器的實現(xiàn)問題,它將復雜的同步器實現(xiàn)分解為簡單的框架方法,開發(fā)者只需要實現(xiàn)少量特定的方法就能快速構(gòu)建出可靠的同步器,這篇文章主要介紹Java AQS原理與ReentrantLock實現(xiàn),需要的朋友可以參考下
    2025-03-03
  • 通過實例了解java spring使用構(gòu)造器注入的原因

    通過實例了解java spring使用構(gòu)造器注入的原因

    這篇文章主要介紹了通過實例了解spring使用構(gòu)造器注入的原因,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-12-12
  • Java運算符從見過到掌握上

    Java運算符從見過到掌握上

    計算機的最基本用途之一就是執(zhí)行數(shù)學運算,作為一門計算機語言,Java也提供了一套豐富的運算符來操縱變量,本篇對大家的學習或工作具有一定的價值,需要的朋友可以參考下
    2021-09-09
  • 詳解如何使用Spring的@FeignClient注解實現(xiàn)通信功能

    詳解如何使用Spring的@FeignClient注解實現(xiàn)通信功能

    SpringBoot是一個非常流行的Java框架,它提供了一系列工具來使這種交互無縫且高效,在這些工具中,@FeignClient注解因其易用性和強大的功能而脫穎而出, 在這篇文章中,我們將探討如何使用Spring的@FeignClient注解進行客戶端-服務器通信,需要的朋友可以參考下
    2023-11-11
  • 解決tomcat啟動時報Junit相關(guān)錯誤java.lang.ClassNotFoundException: org.junit.Test問題

    解決tomcat啟動時報Junit相關(guān)錯誤java.lang.ClassNotFoundException: 

    這篇文章主要介紹了解決tomcat啟動時報Junit相關(guān)錯誤java.lang.ClassNotFoundException: org.junit.Test問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-05-05
  • Java郵件發(fā)送超時時間過長問題的優(yōu)化方案

    Java郵件發(fā)送超時時間過長問題的優(yōu)化方案

    郵件發(fā)送是許多Java應用中常見的功能,尤其在用戶注冊、密碼重置和系統(tǒng)通知中,對于一個高并發(fā)的系統(tǒng)來說,郵件發(fā)送的超時問題可能導致應用性能的下降,甚至影響用戶體驗,因此,本期我們將討論Java郵件發(fā)送超時時間過長 的問題,并深入探討其成因和優(yōu)化策略
    2025-06-06
  • 用java將GBK工程轉(zhuǎn)為uft8的方法實例

    用java將GBK工程轉(zhuǎn)為uft8的方法實例

    本篇文章主要介紹了用java將GBK工程轉(zhuǎn)為uft8的方法實例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-08-08
  • SpringBoot+Redis隊列實現(xiàn)Java版秒殺的示例代碼

    SpringBoot+Redis隊列實現(xiàn)Java版秒殺的示例代碼

    本文主要介紹了SpringBoot+Redis隊列實現(xiàn)Java版秒殺的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-06-06

最新評論

乳源| 金昌市| 黔西县| 韩城市| 日喀则市| 大荔县| 台南县| 金阳县| 公安县| 宜兴市| 宜良县| 新竹市| 当涂县| 太康县| 台湾省| 太谷县| 义乌市| 淮北市| 闸北区| 舞阳县| 罗源县| 镇江市| 林口县| 岳阳县| 遂平县| 双流县| 通许县| 普定县| 南阳市| 浦东新区| 沧州市| 军事| 太谷县| 天全县| 青阳县| 科技| 永登县| 沽源县| 大英县| 兴安盟| 博野县|