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

SpringBoot如何集成Netty

 更新時(shí)間:2024年06月17日 17:01:19   作者:Sea-Man  
這篇文章主要介紹了SpringBoot如何集成Netty問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

一、pom依賴

<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.77.Final</version>
</dependency>
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.5.8</version>
</dependency>

二、配置yml文件

server:
  port: 8001
  servlet:
    context-path: /netty
netty:
  url: 0.0.0.0  #0.0.0.0表示綁定任意ip
  port: 20004

三、服務(wù)端

package com.tlxy.lhn.controller.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class NettyServer {
    public static void main(String[] args) throws InterruptedException {
        //創(chuàng)建兩個(gè)線程組bossGroup和workerGroup,含有的子線程N(yùn)ioEventLoop的個(gè)數(shù)默認(rèn)是CPU的兩倍
        //bossGroup只是處理連接請求,真正的和客戶端業(yè)務(wù)處理,會交給workerGroup完成
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup(1);

        try {
            //創(chuàng)建服務(wù)器端的啟動對象
            ServerBootstrap bootstrap = new ServerBootstrap();
            //使用鏈?zhǔn)骄幊虂砼渲脜?shù)
            bootstrap.group(bossGroup, workerGroup)//設(shè)置兩個(gè)線程組
                    .channel(NioServerSocketChannel.class)//使用NioServerSocketChannel作為服務(wù)器的通道實(shí)現(xiàn)
                    //初始化服務(wù)器連接隊(duì)列大小,服務(wù)端處理客戶端連接請求是順序處理的,所以同一時(shí)間只能處理一個(gè)客戶端連接
                    //多個(gè)客戶端同時(shí)來的時(shí)候,服務(wù)端將不能處理的客戶端連接請求放在隊(duì)列中等待處理
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel channel) throws Exception {
                            //對workerGroup的SocketChannel設(shè)置處理器
                            channel.pipeline().addLast(new NettyServerHandler());
                        }
                    });

            System.out.println("netty server start..");

            //綁定一個(gè)端口并且同步生成一個(gè)ChannelFuture異步對象,通過isDone()等方法可以判斷異步事件的執(zhí)行情況
            //啟動服務(wù)器(并綁定的端口),bind是異步操作,sync方法是等待異步操作執(zhí)行完畢
            ChannelFuture cf = bootstrap.bind(9000).sync();

            //給cf注冊監(jiān)聽器,監(jiān)聽我們關(guān)心的事件
            cf.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture channelFuture) throws Exception {
                    if (cf.isSuccess()) {
                        System.out.println("監(jiān)聽端口9000成功");
                    } else {
                        System.out.println("監(jiān)聽端口9000失敗");
                    }
                }
            });
            //等待服務(wù)端監(jiān)聽端口關(guān)閉,closeFuture是異步操作
            //通過sync方法同步等待通道關(guān)閉處理完畢,這里會阻塞等待通道關(guān)閉完成,內(nèi)部調(diào)用的是Object的wait()方法
            cf.channel().closeFuture().sync();

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


    }
}

NettyServer類中的

channel.pipeline().addLast(new NettyServerHandler());

對應(yīng)以下的處理器。

package com.tlxy.lhn.controller.netty;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class NettyServerHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf buf = (ByteBuf) msg;
        System.out.println("客戶端發(fā)送消息是:" + buf.toString(CharsetUtil.UTF_8));
        // 讀取byteBuf
        // 業(yè)務(wù)處理
        // 回消息給客戶端
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ByteBuf buf = Unpooled.copiedBuffer("HelloClient".getBytes(CharsetUtil.UTF_8));
        ctx.writeAndFlush(buf);
    }

    //只要Netty拋出錯誤就會執(zhí)行,Netty斷會開連接會拋出連接超時(shí)的錯誤
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.info("關(guān)閉通道");
        cause.printStackTrace();
        ctx.close();
    }
}

四、客戶端

package com.tlxy.lhn.controller.netty;

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

public class NettyClient {
    public static void main(String[] args) throws InterruptedException {
        //客戶端需要一個(gè)事件循環(huán)組
        NioEventLoopGroup group = new NioEventLoopGroup();

        try {
            //創(chuàng)建客戶端啟動對象
            //注意客戶端使用的不是SocketBootstrap而是Bootstrap
            Bootstrap bootstrap = new Bootstrap();

            // 設(shè)置相關(guān)參數(shù)
            bootstrap.group(group) //設(shè)置線程組
                    .channel(NioSocketChannel.class)// 使用NioSocketChannel作為客戶端的通道實(shí)現(xiàn)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new NettyClientHandler());
                        }
                    });

            System.out.println("netty client start..");
            ChannelFuture cf = bootstrap.connect("127.0.0.1", 9000).sync();
            cf.channel().closeFuture().sync();
        }finally {
            group.shutdownGracefully();
        }


    }
}

NettyClient類中

ch.pipeline().addLast(new NettyClientHandler());

為處理器。

package com.tlxy.lhn.controller.netty;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class NettyClientHandler extends ChannelInboundHandlerAdapter {

    /**
     * 客戶端連接標(biāo)識
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ByteBuf buf = Unpooled.copiedBuffer("HelloServer".getBytes(CharsetUtil.UTF_8));
        ctx.writeAndFlush(buf);
    }

    //當(dāng)通道建立后有事件時(shí)會觸發(fā),即服務(wù)端發(fā)送數(shù)據(jù)給客戶端
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf buf = (ByteBuf) msg;
        System.out.println("收到服務(wù)端的消息是:" + buf.toString(CharsetUtil.UTF_8));
        System.out.println("服務(wù)端地址是:" + ctx.channel().remoteAddress());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.info("關(guān)閉通道");
        cause.printStackTrace();
        ctx.close();
    }

}

五、粘包和拆包問題

客戶端和服務(wù)端都是固定的框架,我們只需寫處理器。

粘包和拆包問題,可以自己手寫通過固定長度發(fā)送數(shù)據(jù),或者使用Google的Protostuff。

<dependency>
    <groupId>com.dyuproject.protostuff</groupId>
    <artifactId>protostuff-api</artifactId>
    <version>1.0.8</version>
</dependency>
<dependency>
    <groupId>com.dyuproject.protostuff</groupId>
    <artifactId>protostuff-core</artifactId>
    <version>1.0.8</version>
</dependency>
<dependency>
    <groupId>com.dyuproject.protostuff</groupId>
    <artifactId>protostuff-runtime</artifactId>
    <version>1.0.8</version>
</dependency>
package com.tlxy.lhn.controller.netty;

import com.dyuproject.protostuff.LinkedBuffer;
import com.dyuproject.protostuff.ProtostuffIOUtil;
import com.dyuproject.protostuff.Schema;
import com.dyuproject.protostuff.runtime.RuntimeSchema;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ProtostuffUtil {
    private static Map<Class<?>, Schema<?>> cachedSchema = new ConcurrentHashMap<Class<?>, Schema<?>>();

    private static <T> Schema<T> getSchema(Class<T> clazz) {
        @SuppressWarnings("unchecked")
        Schema<T> schema = (Schema<T>) cachedSchema.get(clazz);
        if (schema == null) {
            schema = RuntimeSchema.getSchema(clazz);
            if (schema != null) {
                cachedSchema.put(clazz, schema);
            }
        }
        return schema;
    }

    /**
     * 序列化
     *
     * @param obj
     * @return
     */
    public static <T> byte[] serializer(T obj) {
        @SuppressWarnings("unchecked")
        Class<T> clazz = (Class<T>) obj.getClass();
        LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
        try {
            Schema<T> schema = getSchema(clazz);
            return ProtostuffIOUtil.toByteArray(obj, schema, buffer);
        } catch (Exception e) {
            throw new IllegalStateException(e.getMessage(), e);
        } finally {
            buffer.clear();
        }
    }

    /**
     * 反序列化
     *
     * @param data
     * @param clazz
     * @return
     */
    public static <T> T deserializer(byte[] data, Class<T> clazz) {
        try {
            T obj = clazz.newInstance();
            Schema<T> schema = getSchema(clazz);
            ProtostuffIOUtil.mergeFrom(data, obj, schema);
            return obj;
        } catch (Exception e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
    }

}

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • maven導(dǎo)入本地倉庫jar包,報(bào):Could?not?find?artifact的解決

    maven導(dǎo)入本地倉庫jar包,報(bào):Could?not?find?artifact的解決

    這篇文章主要介紹了maven導(dǎo)入本地倉庫jar包,報(bào):Could?not?find?artifact的解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • SpringBoot實(shí)現(xiàn)Markdown語法轉(zhuǎn)HTML標(biāo)簽的詳細(xì)步驟

    SpringBoot實(shí)現(xiàn)Markdown語法轉(zhuǎn)HTML標(biāo)簽的詳細(xì)步驟

    這篇文章主要介紹了SpringBoot實(shí)現(xiàn)Markdown轉(zhuǎn)HTML的步驟,涵蓋項(xiàng)目配置、測試語法擴(kuò)展(自動鏈接、表情、表格等)、解決GitLab和腳注問題,并添加自定義解析器以確保正確解析,需要的朋友可以參考下
    2025-09-09
  • 淺談一下Spring中的createBean

    淺談一下Spring中的createBean

    createBean是創(chuàng)建Bean的主要方法, 該方法位于:AbstractBeanFactory的doGetBean方法中的createBean調(diào)用。本文就來淺談一下Spring中的createBean?,感興趣的可以了解一下
    2022-07-07
  • SpringBoot多線程進(jìn)行異步請求的處理方式

    SpringBoot多線程進(jìn)行異步請求的處理方式

    這篇文章主要介紹了SpringBoot多線程進(jìn)行異步請求的處理方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜
    2021-12-12
  • @Data注解在Boolean類型屬性上的大坑及解決

    @Data注解在Boolean類型屬性上的大坑及解決

    在使用@Data注解時(shí),如果類中存在Boolean類型的屬性,且屬性名不是以"is"開頭,那么@Data注解生成的get方法名會默認(rèn)加上"is",導(dǎo)致屬性值無法成功拷貝,解決方法是手動添加get方法,覆蓋@Data注解生成的方法
    2024-10-10
  • Java多線程中的CyclicBarrier使用方法詳解

    Java多線程中的CyclicBarrier使用方法詳解

    這篇文章主要介紹了Java多線程中的CyclicBarrier使用方法詳解,CyclicBarrier是一種同步輔助工具,它允許一組線程都等待對方到達(dá)公共障礙點(diǎn),在涉及固定大小的線程的程序中,CyclicBarriers非常有用,這些線程間必須相互等待,需要的朋友可以參考下
    2023-12-12
  • 詳解spring security filter的工作原理

    詳解spring security filter的工作原理

    這篇文章主要介紹了詳解spring security filter的工作原理,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • springboot+thymeleaf國際化之LocaleResolver接口的示例

    springboot+thymeleaf國際化之LocaleResolver接口的示例

    本篇文章主要介紹了springboot+thymeleaf國際化之LocaleResolver的示例 ,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-11-11
  • mybatis-plus 如何判斷參數(shù)是否為空并作為查詢條件

    mybatis-plus 如何判斷參數(shù)是否為空并作為查詢條件

    這篇文章主要介紹了mybatis-plus 如何判斷參數(shù)是否為空并作為查詢條件,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • 一文讓你徹底明白Java中的值傳遞和引用傳遞

    一文讓你徹底明白Java中的值傳遞和引用傳遞

    這篇文章主要給大家介紹了關(guān)于Java中值傳遞和引用傳遞的相關(guān)資料,值傳遞是指在調(diào)用函數(shù)時(shí)將實(shí)際參數(shù)復(fù)制一份傳遞到函數(shù)中,引用傳遞是指在調(diào)用函數(shù)時(shí)將實(shí)際參數(shù)的引用直接傳遞到函數(shù)中,需要的朋友可以參考下
    2023-10-10

最新評論

斗六市| 资溪县| 类乌齐县| 武安市| 台东县| 黄石市| 眉山市| 林口县| 房山区| 沁水县| 清水县| 弥勒县| 曲阳县| 紫阳县| 陈巴尔虎旗| 阜新市| 舟曲县| 温州市| 巩义市| 从江县| 灵台县| 霸州市| 孙吴县| 本溪市| 斗六市| 丽水市| 玛沁县| 建湖县| 晋城| 紫金县| 高陵县| 阳城县| 湘乡市| 霍邱县| 安溪县| 武山县| 甘泉县| 阿鲁科尔沁旗| 临沭县| 奉贤区| 浏阳市|