欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot集成netty實(shí)現(xiàn)websocket通信功能

 更新時(shí)間:2024年03月14日 09:11:44   作者:A塵埃  
Netty是一個(gè)高性能、異步事件驅(qū)動的網(wǎng)絡(luò)應(yīng)用框架,用于快速開發(fā)可維護(hù)的高性能協(xié)議服務(wù)器和客戶端,WebSocket 是一種網(wǎng)絡(luò)通信協(xié)議,相比傳統(tǒng)的HTTP協(xié)議,本文給大家介紹了SpringBoot集成netty實(shí)現(xiàn)websocket通信功能,需要的朋友可以參考下

實(shí)現(xiàn)推送消息給指定的用戶

一、依賴

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springboot-demo</artifactId>
        <groupId>com.et</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>netty</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.87.Final</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.6.1</version>
        </dependency>
    </dependencies>
</project>

二、屬性文件和啟動類

server:
  port: 8088

三、Controller接口

@RestController
@RequestMapping("/push")
public class TestController{
	
	@Autowired
	PushMsgService pushMsgService
}

四、PushMsgService

public interface PushMsgService{
	
	//推送給指定用戶
	void pushMsgToOne(String userId,String msg);

	//推送給所有用戶
	void pushMsgToAll(String msg);
}
@Service
public class PushMsgServiceImpl implements PushMsgService{
	
	@Override
	public void pushMsgToOne(String userId, String msg){
		Channel channel = NettyConfig.getChannel(userId);
        if (Objects.isNull(channel)) {
            throw new RuntimeException("未連接socket服務(wù)器");
        }

        channel.writeAndFlush(new TextWebSocketFrame(msg));
	}

	@Override
	public void pushMsgToAll(String msg){
		NettyConfig.getChannelGroup().writeAndFlush(new TextWebSocketFrame(msg));
	}
}

五、NettyConfig

public class NettyConfig{
	
	//定義全局channel,管理所有的channel
	private static volatile ChannelGroup channelGroup = null;

	//存放請求ID與channel的對應(yīng)關(guān)系
	private static volatile ConcurrentHashMap<String, Channel> channelMap = null;

	//定義兩把鎖
	private static final Object lock1 = new Object();
    private static final Object lock2 = new Object();

	public static ChannelGroup getChannelGroup() {
        if (null == channelGroup) {
            synchronized (lock1) {
                if (null == channelGroup) {
                    channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
                }
            }
        }
        return channelGroup;
    }

    public static ConcurrentHashMap<String, Channel> getChannelMap() {
        if (null == channelMap) {
            synchronized (lock2) {
                if (null == channelMap) {
                    channelMap = new ConcurrentHashMap<>();
                }
            }
        }
        return channelMap;
    }

    public static Channel getChannel(String userId) {
        if (null == channelMap) {
            return getChannelMap().get(userId);
        }
        return channelMap.get(userId);
    }
}

六、netty server

@Component
public class NettyServer {
    static final Logger log = LoggerFactory.getLogger(NettyServer.class);

    /**
     * 端口號
     */
    @Value("${webSocket.netty.port:8889}")
    int port;

    EventLoopGroup bossGroup;
    EventLoopGroup workGroup;

    @Autowired
    ProjectInitializer nettyInitializer;

    @PostConstruct
    public void start() throws InterruptedException {
        new Thread(() -> {
            bossGroup = new NioEventLoopGroup();
            workGroup = new NioEventLoopGroup();
            ServerBootstrap bootstrap = new ServerBootstrap();
            // bossGroup輔助客戶端的tcp連接請求, workGroup負(fù)責(zé)與客戶端之前的讀寫操作
            bootstrap.group(bossGroup, workGroup);
            // 設(shè)置NIO類型的channel
            bootstrap.channel(NioServerSocketChannel.class);
            // 設(shè)置監(jiān)聽端口
            bootstrap.localAddress(new InetSocketAddress(port));
            // 設(shè)置管道
            bootstrap.childHandler(nettyInitializer);

            // 配置完成,開始綁定server,通過調(diào)用sync同步方法阻塞直到綁定成功
            ChannelFuture channelFuture = null;
            try {
                channelFuture = bootstrap.bind().sync();
                log.info("Server started and listen on:{}", channelFuture.channel().localAddress());
                // 對關(guān)閉通道進(jìn)行監(jiān)聽
                channelFuture.channel().closeFuture().sync();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }

    /**
     * 釋放資源
     */
    @PreDestroy
    public void destroy() throws InterruptedException {
        if (bossGroup != null) {
            bossGroup.shutdownGracefully().sync();
        }
        if (workGroup != null) {
            workGroup.shutdownGracefully().sync();
        }
    }
}

七、ProjectInitializer初始化,設(shè)置websocket handler

@Component
public class ProjectInitializer extends ChannelInitializer<SocketChannel> {

    /**
     * webSocket協(xié)議名
     */
    static final String WEBSOCKET_PROTOCOL = "WebSocket";

    /**
     * webSocket路徑
     */
    @Value("${webSocket.netty.path:/webSocket}")
    String webSocketPath;
    @Autowired
    WebSocketHandler webSocketHandler;

    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        // 設(shè)置管道
        ChannelPipeline pipeline = socketChannel.pipeline();
        // 流水線管理通道中的處理程序(Handler),用來處理業(yè)務(wù)
        // webSocket協(xié)議本身是基于http協(xié)議的,所以這邊也要使用http編解碼器
        pipeline.addLast(new HttpServerCodec());
        pipeline.addLast(new ObjectEncoder());
        // 以塊的方式來寫的處理器
        pipeline.addLast(new ChunkedWriteHandler());
        pipeline.addLast(new HttpObjectAggregator(8192));
        pipeline.addLast(new WebSocketServerProtocolHandler(webSocketPath, WEBSOCKET_PROTOCOL, true, 65536 * 10));
        // 自定義的handler,處理業(yè)務(wù)邏輯
        pipeline.addLast(webSocketHandler);
    }
}

八、WebSocketHandler

@Component
@ChannelHandler.Sharable
public class WebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
    private static final Logger log = LoggerFactory.getLogger(NettyServer.class);

    /**
     * 一旦連接,第一個(gè)被執(zhí)行
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        log.info("有新的客戶端鏈接:[{}]", ctx.channel().id().asLongText());
        // 添加到channelGroup 通道組
        NettyConfig.getChannelGroup().add(ctx.channel());
    }

    /**
     * 讀取數(shù)據(jù)
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        log.info("服務(wù)器收到消息:{}", msg.text());

        // 獲取用戶ID,關(guān)聯(lián)channel
        JSONObject jsonObject = JSONUtil.parseObj(msg.text());
        String uid = jsonObject.getStr("uid");
        NettyConfig.getChannelMap().put(uid, ctx.channel());

        // 將用戶ID作為自定義屬性加入到channel中,方便隨時(shí)channel中獲取用戶ID
        AttributeKey<String> key = AttributeKey.valueOf("userId");
        ctx.channel().attr(key).setIfAbsent(uid);

        // 回復(fù)消息
        ctx.channel().writeAndFlush(new TextWebSocketFrame("服務(wù)器收到消息啦"));
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        log.info("用戶下線了:{}", ctx.channel().id().asLongText());
        // 刪除通道
        NettyConfig.getChannelGroup().remove(ctx.channel());
        removeUserId(ctx);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.info("異常:{}", cause.getMessage());
        // 刪除通道
        NettyConfig.getChannelGroup().remove(ctx.channel());
        removeUserId(ctx);
        ctx.close();
    }

    /**
     * 刪除用戶與channel的對應(yīng)關(guān)系
     */
    private void removeUserId(ChannelHandlerContext ctx) {
        AttributeKey<String> key = AttributeKey.valueOf("userId");
        String userId = ctx.channel().attr(key).get();
        NettyConfig.getChannelMap().remove(userId);
    }
}

測試:

postman創(chuàng)建websocket連接 ws://127.0.0.1:8889/webSocket,并發(fā)送消息{‘uid’:‘sss’}給服務(wù)端

在這里插入圖片描述

打開瀏覽器,給用戶sss推送消息 http://127.0.0.1:8088/push/sss

在這里插入圖片描述

以上就是SpringBoot集成netty實(shí)現(xiàn)websocket通信功能的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot netty websocket通信的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Spring Security OAuth2集成短信驗(yàn)證碼登錄以及第三方登錄

    Spring Security OAuth2集成短信驗(yàn)證碼登錄以及第三方登錄

    這篇文章主要介紹了Spring Security OAuth2集成短信驗(yàn)證碼登錄以及第三方登錄,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-04-04
  • 深入了解Java行為型設(shè)計(jì)模式之策略模式

    深入了解Java行為型設(shè)計(jì)模式之策略模式

    策略模式屬于Java-設(shè)計(jì)模式中行為模式之一,該模式定義了一系列算法,并將每個(gè)算法封裝起來,使它們可以相互替換。本文將通過示例詳細(xì)講解這一模式,需要的可以參考一下
    2022-09-09
  • Java實(shí)現(xiàn)對稱加密DES和AES的示例代碼

    Java實(shí)現(xiàn)對稱加密DES和AES的示例代碼

    這篇文章主要介紹了如何使用Java實(shí)現(xiàn)采用對稱密碼算法的應(yīng)用軟件,所用算法包括DES算法和AES算法,文中的示例代碼講解詳細(xì),感興趣的可以了解一下
    2023-04-04
  • Java實(shí)現(xiàn)精準(zhǔn)Excel數(shù)據(jù)排序的方法詳解

    Java實(shí)現(xiàn)精準(zhǔn)Excel數(shù)據(jù)排序的方法詳解

    在數(shù)據(jù)處理或者數(shù)據(jù)分析的場景中,需要對已有的數(shù)據(jù)進(jìn)行排序,在Excel中可以通過排序功能進(jìn)行整理數(shù)據(jù),而在Java中,則可以借助Excel表格插件對數(shù)據(jù)進(jìn)行批量排序,下面我們就來學(xué)習(xí)一下常見的數(shù)據(jù)排序方法吧
    2023-10-10
  • 詳解java中通過post方式訪問后臺服務(wù)器

    詳解java中通過post方式訪問后臺服務(wù)器

    本篇文章主要介紹了詳解java中通過post方式訪問后臺服務(wù)器,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2017-03-03
  • SSM項(xiàng)目實(shí)現(xiàn)短信驗(yàn)證碼登錄功能的示例代碼

    SSM項(xiàng)目實(shí)現(xiàn)短信驗(yàn)證碼登錄功能的示例代碼

    這篇文章主要為大家分享了在SSM項(xiàng)目中實(shí)現(xiàn)短信驗(yàn)證碼登錄功能的示例代碼,文中的實(shí)現(xiàn)步驟講解詳細(xì),感興趣的小伙伴可以跟隨小編一起動手嘗試一下
    2022-05-05
  • Spring?Data?Jpa?中原生查詢?REGEXP?的使用詳解

    Spring?Data?Jpa?中原生查詢?REGEXP?的使用詳解

    這篇文章主要介紹了Spring?Data?Jpa?中原生查詢?REGEXP?的使用詳解,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Caffeine本地緩存示例詳解

    Caffeine本地緩存示例詳解

    Caffeine是一種高性能的緩存庫,是基于Java 8的最佳(最優(yōu))緩存框架,這篇文章主要介紹了Caffeine本地緩存相關(guān)知識,需要的朋友可以參考下
    2023-07-07
  • Java實(shí)戰(zhàn)房屋租賃網(wǎng)的實(shí)現(xiàn)流程

    Java實(shí)戰(zhàn)房屋租賃網(wǎng)的實(shí)現(xiàn)流程

    讀萬卷書不如行萬里路,只學(xué)書上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實(shí)戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用java+SSM+jsp+mysql+maven實(shí)現(xiàn)一個(gè)房屋租賃網(wǎng)站,大家可以在過程中查缺補(bǔ)漏,提升水平
    2021-11-11
  • maven快速生成SpringBoot打包文件的方法步驟

    maven快速生成SpringBoot打包文件的方法步驟

    本文主要介紹了使用Maven快速生成SpringBoot項(xiàng)目打包文件的方法,包括如何生成可執(zhí)行的JAR文件,如何將配置文件、運(yùn)行腳本、調(diào)試腳本、證書文件等拷貝到指定目錄,及如何編譯出部署包,這種方法能大大方便微服務(wù)的部署,提高部署效率
    2024-10-10

最新評論