Netty+Websocket实现简单的回声聊天服务器
Netty Websocket 回声聊天室案例
讲解参照我netty聊天室的博客
Demo源码地址https://gitee.com/HumorChen/netty_websocket_demo 仅供参考
-
项目名
netty_websocket_demo
-
Maven依赖
完整依赖在最后
<!--netty的依赖集合,都整合在一个依赖里面了--> <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.25.Final</version> </dependency>
-
NettyWebServer类
package com.example.netty_websocket_demo.server; import com.example.netty_websocket_demo.handler.NettyWebSocketHandler; 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; 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 (){ //boss线程组用来接收连接 EventLoopGroup boss=new NioEventLoopGroup(); //worker线程组用来处理消息 EventLoopGroup worker=new NioEventLoopGroup(); try { //辅助启动工具类 ServerBootstrap bootstrap=new ServerBootstrap(); bootstrap.group(boss,worker).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() { @Override protected 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)); //协议处理器 pipeline.addLast(new WebSocketServerProtocolHandler("/ws")); //自定义的处理器 pipeline.addLast(new NettyWebSocketHandler()); } }); //绑定端口,同步启动 ChannelFuture future=bootstrap.bind(8081).sync(); future.channel().closeFuture().sync(); }catch (Exception e){ e.printStackTrace(); }finally { boss.shutdownGracefully(); worker.shutdownGracefully(); } } public static void main(String[] args) { run(); } }
-
NettyWebSocketHandler类
package com.example.netty_websocket_demo.handler; import io.netty.channel.*; import io.netty.channel.group.ChannelGroup; import io.netty.channel.group.DefaultChannelGroup; import io.netty.handler.codec.http.websocketx.*; import io.netty.util.concurrent.GlobalEventExecutor; /** * NettyWebsocket文本消息处理器 */ public class NettyWebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> { // 用于记录和管理所有客户端的channle private static ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); @Override protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception { // 获取客户端传输过来的消息 String content = msg.text(); System.out.println("服务器接收到的数据:" + content); //群发给所有连接 // for (Channel channel: clients) { // channel.writeAndFlush( // new TextWebSocketFrame( // "[服务器在]" + LocalDateTime.now() // + "接受到消息, 消息为:" + content)); // } // 下面这个方法,和上面的for循环,一致 向客户端发送数据 clients.writeAndFlush(new TextWebSocketFrame("我是服务器,我收到你的消息为:" + content)); } /** * 当客户端连接服务端之后(打开连接) * 获取客户端的channle,并且放到ChannelGroup中去进行管理 */ @Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { clients.add(ctx.channel()); } @Override public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { // 当触发handlerRemoved,ChannelGroup会自动移除对应客户端的channel,所以下面的remove不用我们再手写 // clients.remove(ctx.channel()); System.out.println("客户端断开,channle对应的长id为:" + ctx.channel().id().asLongText()); System.out.println("客户端断开,channle对应的短id为:" + ctx.channel().id().asShortText()); } }
-
验证使用SpringBoot和一个html页面
-
Application类
package com.example.netty_websocket_demo; import com.example.netty_websocket_demo.server.NettyWebServer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.ApplicationListener; @SpringBootApplication public class NettyWebsocketDemoApplication implements ApplicationListener<ApplicationReadyEvent> { public static void main(String[] args) { SpringApplication.run(NettyWebsocketDemoApplication.class, args); } @Override public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) { //springboot启动完成后启动netty NettyWebServer.run(); } }
-
Html页面
index.html (src\main\resources\static\index.html)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>WebSocketTest</title> <script> url='ws://localhost:8081/ws' if (!window.WebSocket) { window.WebSocket = window.MozWebSocket } if (window.WebSocket) { socket = new WebSocket(url) socket.onopen = function(event) { addMsg('连接成功') console.log(event) } socket.onclose = function(event) { addMsg('连接被关闭') } socket.onmessage = function(event) { addMsg("【服务器】:"+event.data) } } else { alert('你的浏览器不支持 WebSocket!') } function addMsg(msg) { let content=document.getElementById('content') content.innerHTML=content.innerHTML+msg+"<br>" } function send() { let msg=document.getElementById('input').value if(msg){ if (!window.WebSocket) { return } if (socket.readyState == WebSocket.OPEN) { socket.send(msg) addMsg("【客户端】:"+msg) document.getElementById('input').value='' } else { alert('连接没有开启.') } }else{ alert('不允许空消息') } } </script> </head> <body> <div id="content" style="width: 800px;height: 600px;"> </div> <div style="width: 800px;height: 120px"> <textarea id="input" placeholder="请输入短信内容" style="width: 100%;height: 80px"></textarea> <button onclick="send()">发送</button> </div> </body> </html>
- 启动 NettyWebsocketDemoApplication - 浏览器访问localhost即可测试
本文来自博客园,作者:HumorChen99,转载请注明原文链接:https://www.cnblogs.com/HumorChen/p/18039683
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~