日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Netty Websocket多人多房间聊天室Demo

發(fā)布時(shí)間:2023/12/20 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Netty Websocket多人多房间聊天室Demo 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Netty Websocket多人多房間聊天室Demo

描述:可任意輸入自己的昵稱和要加入的聊天室名,即可加入聊天室進(jìn)行聊天,在同一個(gè)聊天室內(nèi)的所有人的發(fā)言每個(gè)人都會(huì)立即收到

項(xiàng)目使用springboot,源碼https://download.csdn.net/download/HumorChen99/15843430
https://gitee.com/HumorChen/netty_websocket_chatroom_demo

主要是這么些步驟:

  • 建立兩個(gè)事件輪詢組NioEventLoopGroup,一個(gè)用來處理連接的建立,一個(gè)用來處理消息的處理
  • 建立一個(gè)啟動(dòng)器ServerBootstrap,方便我們啟動(dòng)netty服務(wù)器
  • 綁定啟動(dòng)器的輪詢組bootstrap.group(boss,worker)
  • 指定使用Nio管道非阻塞.channel(NioServerSocketChannel.class)
  • 配置管道初始化器.childHandler(new ChannelInitializer() {…}
  • 在初始化器里配置一系列的處理器handler
  • 然后綁定端口同步啟動(dòng)netty服務(wù)器
    • 處理器里分為兩個(gè)自定義的,一個(gè)是處理http的一個(gè)是處理ws消息的。

    因?yàn)閯?chuàng)建ws的時(shí)候第一次是發(fā)的一個(gè)http請(qǐng)求,所以我們利用這次http請(qǐng)求來完成加入聊天室的操作,讓發(fā)起ws的時(shí)候url里帶入昵稱和聊天室名字的參數(shù),然后握手之前先得到這些參數(shù)用來初始化,然后繼續(xù)握手創(chuàng)建管道,然后把管道放入到這個(gè)聊天室的管道組,如果某個(gè)管道來了消息,那么要群發(fā)給管道里的每個(gè)人(要從管道知道是哪個(gè)聊天室的,以及這個(gè)用戶名稱,那么我們?cè)诔跏蓟臅r(shí)候?qū)⑿畔⒋嫒肓斯艿赖膶傩岳锶チ薬ttr)。

    處理消息的時(shí)候是責(zé)任鏈模式,每個(gè)handler依次執(zhí)行,直到某個(gè)handler處理掉這個(gè)消息

    • 依賴

      <!--netty的依賴集合,都整合在一個(gè)依賴?yán)锩媪?-> <dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.25.Final</version> </dependency>
    • NettyWebServer 創(chuàng)建Netty服務(wù)器

      package com.example.netty_websocket_chatroom_demo.server;import com.example.netty_websocket_chatroom_demo.handler.ChatHandler; import com.example.netty_websocket_chatroom_demo.handler.HttpHandler; 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; import io.netty.handler.codec.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpServerCodec; import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; import io.netty.handler.stream.ChunkedWriteHandler;public class NettyWebServer {public static void run(){EventLoopGroup boss=new NioEventLoopGroup();EventLoopGroup worker=new NioEventLoopGroup();try {ServerBootstrap bootstrap=new ServerBootstrap();bootstrap.group(boss,worker).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline=ch.pipeline();//http編碼解碼器pipeline.addLast(new HttpServerCodec());//分塊傳輸pipeline.addLast(new ChunkedWriteHandler());//塊聚合pipeline.addLast(new HttpObjectAggregator(1024*1024));//進(jìn)入聊天室的http處理器pipeline.addLast(new HttpHandler());//協(xié)議處理器 // pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));//自定義的處理器pipeline.addLast(new ChatHandler());}});ChannelFuture channelFuture=bootstrap.bind(8081).sync();channelFuture.channel().closeFuture().sync();}catch (Exception e){e.printStackTrace();}finally {boss.shutdownGracefully();worker.shutdownGracefully();}} }
    • HttpHandler用來處理升級(jí)協(xié)議的http請(qǐng)求并同時(shí)處理加入聊天室的操作

      package com.example.netty_websocket_chatroom_demo.handler;import com.example.netty_websocket_chatroom_demo.constant.ChatroomConst; import com.example.netty_websocket_chatroom_demo.data.ChatRoom; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.*; import io.netty.channel.group.ChannelGroup; import io.netty.channel.group.DefaultChannelGroup; import io.netty.handler.codec.http.*; import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker; import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory; import io.netty.util.AttributeKey; import io.netty.util.CharsetUtil; import io.netty.util.concurrent.ImmediateEventExecutor;import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.util.Map;public class HttpHandler extends SimpleChannelInboundHandler<FullHttpRequest> {private WebSocketServerHandshaker handshaker;static {AttributeKey.newInstance(ChatroomConst.IP);AttributeKey.newInstance(ChatroomConst.USERNAME);AttributeKey.newInstance(ChatroomConst.CHATROOM);}@Overrideprotected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception {QueryStringDecoder decoder=new QueryStringDecoder(req.uri());String chatroomName=decoder.parameters().get("chatroom").get(0);String nickName=decoder.parameters().get("nickname").get(0);if(chatroomName==null || "".equals(chatroomName) || nickName==null || "".equals(nickName) || !req.decoderResult().isSuccess()||!"websocket".equals(req.headers().get("Upgrade"))){FullHttpResponse response=new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST);ChannelFuture future=ctx.channel().writeAndFlush(response);future.addListener(ChannelFutureListener.CLOSE);}else{//獲取IPString ip=((InetSocketAddress)ctx.channel().remoteAddress()).getAddress().getHostAddress();if("0:0:0:0:0:0:0:1".equals(ip)){ip="127.0.0.1";}String username=nickName+"("+ip+")";ctx.channel().attr(AttributeKey.valueOf(ChatroomConst.IP)).set(ip);ctx.channel().attr(AttributeKey.valueOf(ChatroomConst.USERNAME)).set(username);ctx.channel().attr(AttributeKey.valueOf(ChatroomConst.CHATROOM)).set(chatroomName);WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(req.uri(), null, false);handshaker = wsFactory.newHandshaker(req);if (handshaker == null) {WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());} else {handshaker.handshake(ctx.channel(), req).sync();ChannelGroup channelGroup=ChatRoom.map.get(chatroomName);if(channelGroup==null){channelGroup=new DefaultChannelGroup(ImmediateEventExecutor.INSTANCE);channelGroup.add(ctx.channel());ChatRoom.map.put(chatroomName,channelGroup);}else{TextWebSocketFrame textWebSocketFrame=new TextWebSocketFrame(username+" 加入了聊天室");for(Channel channel:channelGroup){channel.writeAndFlush(textWebSocketFrame);}channelGroup.add(ctx.channel());}}}}@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {System.out.println("通道建立");super.channelActive(ctx);}@Overridepublic void channelInactive(ChannelHandlerContext ctx) throws Exception {System.out.println("通道關(guān)閉");String chatroom=(String) ctx.channel().attr(AttributeKey.valueOf(ChatroomConst.CHATROOM)).get();if(chatroom!=null){ChannelGroup channelGroup=ChatRoom.map.get(chatroom);channelGroup.remove(ctx.channel());}super.channelInactive(ctx);} }
    • ChatHandler 聊天信息的處理器

      package com.example.netty_websocket_chatroom_demo.handler;import com.example.netty_websocket_chatroom_demo.constant.ChatroomConst; import com.example.netty_websocket_chatroom_demo.data.ChatRoom; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.group.ChannelGroup; import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; import io.netty.util.AttributeKey;import java.util.Date;public class ChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {String text=msg.text();String username=(String) ctx.channel().attr(AttributeKey.valueOf(ChatroomConst.USERNAME)).get();String chatroom=(String) ctx.channel().attr(AttributeKey.valueOf(ChatroomConst.CHATROOM)).get();String id=ctx.channel().id().asLongText();if(chatroom!=null){ChannelGroup channelGroup= ChatRoom.map.get(chatroom);if(channelGroup!=null){String time=new Date().toLocaleString();TextWebSocketFrame other=new TextWebSocketFrame(time+" "+username+": "+text);TextWebSocketFrame me=new TextWebSocketFrame(time+" "+"我: "+text);for(Channel channel:channelGroup){String channelId=channel.id().asLongText();if(id.equals(channelId)){channel.writeAndFlush(me);}else {channel.writeAndFlush(other);}}}}} }
    • ChatRoom 用來存放聊天室和每個(gè)聊天室里的channel

      package com.example.netty_websocket_chatroom_demo.data;import io.netty.channel.group.ChannelGroup;import java.util.HashMap; import java.util.Map;/*** 存放每個(gè)聊天室和每個(gè)聊天室里的數(shù)據(jù)*/ public class ChatRoom {public static Map<String, ChannelGroup> map=new HashMap<>(); }
    • ChatroomConst 常量類

      package com.example.netty_websocket_chatroom_demo.constant;/*** 常量*/ public interface ChatroomConst {String IP="IP";String USERNAME="USERNAME";String CHATROOM="CHATROOM"; }
    • 測(cè)試頁面

      <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>WebSocketTest</title><script>socket=undefined/*** 往屏幕里輸出信息*/function addMsg(msg) {let content=document.getElementById('content')content.innerHTML=content.innerHTML+msg+"<br>"}function send() {let msg=document.getElementById('input').valueif(msg){if (!window.WebSocket) {return}if (socket.readyState == WebSocket.OPEN) {socket.send(msg)document.getElementById('input').value=''} else {alert('連接沒有開啟.')}}else{alert('不允許空消息')}}/*** 加入聊天室*/function enter() {nickname=document.getElementById('nickname').valuechatroom=document.getElementById('chatroom').valueurl='ws://192.168.0.140:8081/ws?nickname='+nickname+'&chatroom='+chatroomif (!window.WebSocket) {window.WebSocket = window.MozWebSocket}if (window.WebSocket) {socket = new WebSocket(url)socket.onopen = function(event) {addMsg('聊天室'+chatroom+' 連接成功')console.log(event)}socket.onclose = function(event) {addMsg('連接被關(guān)閉')}socket.onmessage = function(event) {addMsg(event.data)}} else {alert('你的瀏覽器不支持 WebSocket!')}}/*** 退出聊天室*/async function exit() {socket.close()addMsg("退出聊天室")}</script> </head> <body> <div id="content" style="width: 400px;height: 300px;"></div> <div style="width: 400px;height: 200px"><input type="text" id="nickname" placeholder="請(qǐng)輸入要使用的昵稱"><input type="text" id="chatroom" placeholder="請(qǐng)輸入要加入的聊天室名"><button onclick="enter()">進(jìn)入聊天室</button><textarea id="input" placeholder="請(qǐng)輸入短信內(nèi)容" style="width: 100%;height: 80px"></textarea><button onclick="send()">發(fā)送</button><button onclick="exit()">退出聊天室</button> </div> </body> </html>
    • application.yml 項(xiàng)目配置

      server:port: 80
    • 完整maven pom.xml

      <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.4.0</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.example</groupId><artifactId>netty_websocket_chatroom_demo</artifactId><version>1.0.1-SNAPSHOT</version><name>netty_websocket_chatroom_demo</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version></properties><dependencies><!--netty的依賴集合,都整合在一個(gè)依賴?yán)锩媪?-><dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.25.Final</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build> </project>

    總結(jié)

    以上是生活随笔為你收集整理的Netty Websocket多人多房间聊天室Demo的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。