赞
踩
效果演示视频和教学讲解视频地址:演示地址
注意:先启动SpringBoot项目,再启动WebSocketServer!!!
代码:
1.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 http://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.2.5.RELEASE</version><!--2.3.3.RELEASE--> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.yjq.programmer</groupId> <artifactId>ChatDemo</artifactId> <version>1.0-SNAPSHOT</version> <name>ChatDemo</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <!-- 整合web开发依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 整合netty开发依赖 --> <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.42.Final</version> </dependency> </dependencies> <build> <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) --> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </pluginManagement> </build> </project>
2.WebSocketServer代码:
package com.yjq.programmer.websocket; import com.yjq.programmer.netty.HelloServerInitializer; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; /** * @author 杨杨吖 * @QQ 823208782 * @WX yjqi12345678 * @create 2022-10-03 8:28 */ public class WebSocketServer { public static void main(String[] args) throws Exception { // 定义一对线程组 主线程组 用于接收客户端的连接请求,不做任何处理 EventLoopGroup bossGroup = new NioEventLoopGroup(); // 定义一对线程组 从线程组 主线程组会把任务丢给从线程组,让从线程组去处理 EventLoopGroup workerGroup = new NioEventLoopGroup(); try { // netty服务器的创建,ServerBootstrap是一个启动类 ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(bossGroup, workerGroup) // 设置主从线程组 .channel(NioServerSocketChannel.class) // 设置NIO双向通道类型 .childHandler(new WebSocketServerInitializer()); // 子处理器,用于处理workerGroup // 启动server,绑定8088端口启动,并且同步等待方式启动 ChannelFuture channelFuture = serverBootstrap.bind(8088).sync(); // 监听关闭的channel, 设置为同步的方式 channelFuture.channel().closeFuture().sync(); } finally { // 关闭我们的主线程组和从线程组 bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } }
3.WebSocketServerInitializer代码:
package com.yjq.programmer.websocket; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; 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; /** * @author 杨杨吖 * @QQ 823208782 * @WX yjqi12345678 * @create 2022-10-03 8:34 */ public class WebSocketServerInitializer extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel channel) throws Exception { // 通过SocketChannel去获取对应的管道pipeline ChannelPipeline pipeline = channel.pipeline(); // 通过管道,添加handler HttpServerCodec是netty自己提供的助手类 // 当请求到服务端时候,我们需要做解码,响应到客户端时候需要做编码 pipeline.addLast("HttpServerCodec", new HttpServerCodec()); // 对写大数据流的支持 pipeline.addLast("ChunkedWriteHandler", new ChunkedWriteHandler()); // 对HttpMessage进行聚合 聚合成FullHttpRequest或FullHttpResponse // 几乎在netty的编程中,都会用到这个handler pipeline.addLast("HttpObjectAggregator", new HttpObjectAggregator(1024*64)); // 以上用于支持http协议 // websocket服务器处理的协议 并且用于指定给客户端连接访问的路由:/ws pipeline.addLast("WebSocketServerProtocolHandler", new WebSocketServerProtocolHandler("/ws")); // 自定义的handler pipeline.addLast(new ChatHandler()); } }
4.ChatHandler代码:
package com.yjq.programmer.websocket; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.group.ChannelGroup; import io.netty.channel.group.DefaultChannelGroup; import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; import io.netty.util.concurrent.GlobalEventExecutor; /** * @author 杨杨吖 * @QQ 823208782 * @WX yjqi12345678 * @create 2022-10-03 8:50 */ /** * 处理消息的handler * TextWebSocketFrame:在netty中,是用于为websocket专门处理文本的对象,frame是消息的载体 */ public class ChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> { // 用于记录和管理所有客户端的ChannelGroup 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) { // 不能直接writeAndFlush收到的content字符串信息,必须封装到frame载体中输出 channel.writeAndFlush(new TextWebSocketFrame("系统消息:" + content)); } // clients.writeAndFlush(new TextWebSocketFrame("系统消息:" + content)); } @Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { // 当客户端连接服务端之后,获取客户端的channel,并且放到ChannelGroup中去进行管理 clients.add(ctx.channel()); } @Override public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { // 这步是多余的,当断开连接时候ChannelGroup会自动移除对应的channel clients.remove(ctx.channel()); System.out.println(ctx.channel().id().asLongText()); } }
5.index.html代码:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Netty-Websocket</title> <script type="text/javascript"> let socket; if(window.WebSocket){ socket = new WebSocket("ws://localhost:8088/ws"); socket.onmessage = function(event){ let textarea = document.getElementById('responseText'); textarea.value += event.data+"\r\n"; }; socket.onopen = function(event){ let textarea = document.getElementById('responseText'); textarea.value = "Netty-WebSocket服务器。。。。。。连接 \r\n"; }; socket.onclose = function(event){ let textarea = document.getElementById('responseText'); textarea.value = "Netty-WebSocket服务器。。。。。。关闭 \r\n"; }; } else { alert("您的浏览器不支持WebSocket协议!"); } function send(){ if(!window.WebSocket){return;} if(socket.readyState === WebSocket.OPEN) { let message = document.getElementById('message').value; socket.send(message); } else { alert("WebSocket 连接没有建立成功!"); } } </script> </head> <body> <form onSubmit="return false;"> <label>文本</label><input type="text" id="message" name="message" placeholder="这里输入消息" /> <br /> <br /> <input type="button" value="发送ws消息" onClick="send()" /> <hr color="black" /> <h3>服务端返回的应答消息</h3> <textarea id="responseText" style="width: 1024px;height: 300px;"></textarea> </form> </body> </html>
6.项目结构及配置文件:
完整的配套代码资料获取请关注公众号:杨杨吖知识库,回复关键词:配套代码资料
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。