From 63c5024bea722b5cec8c4395f56afe2ecf01bc22 Mon Sep 17 00:00:00 2001 From: MartyJ28 <1578128844@qq.com> Date: Sun, 27 Oct 2024 20:35:34 +0800 Subject: [PATCH] Demo netty 2 --- .../com/example/demo/DemoApplication.java | 6 +- .../example/demo/Service/WebSocketServer.java | 64 +++++++++++++++++++ .../demo/Service/WebSocketServerHandler.java | 48 ++++++++++++++ src/main/resources/application.properties | 2 + 4 files changed, 117 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/example/demo/Service/WebSocketServer.java create mode 100644 src/main/java/com/example/demo/Service/WebSocketServerHandler.java diff --git a/src/main/java/com/example/demo/DemoApplication.java b/src/main/java/com/example/demo/DemoApplication.java index c7e65f2..588f528 100644 --- a/src/main/java/com/example/demo/DemoApplication.java +++ b/src/main/java/com/example/demo/DemoApplication.java @@ -1,6 +1,7 @@ package com.example.demo; import com.example.demo.Entity.Person; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext; @@ -9,13 +10,12 @@ import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication @EnableScheduling //开启定时任务 public class DemoApplication { + + public static void main(String[] args) { ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args); System.out.println(run.getBeanDefinitionCount()); - - System.out.println(); - } } diff --git a/src/main/java/com/example/demo/Service/WebSocketServer.java b/src/main/java/com/example/demo/Service/WebSocketServer.java new file mode 100644 index 0000000..a9adb71 --- /dev/null +++ b/src/main/java/com/example/demo/Service/WebSocketServer.java @@ -0,0 +1,64 @@ +package com.example.demo.Service; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +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; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; + +@Component +public class WebSocketServer { + + @Value("${netty.port}") + private int port; + + private final WebSocketServerHandler webSocketServerHandler; + + public WebSocketServer(WebSocketServerHandler webSocketServerHandler) { + this.webSocketServerHandler = webSocketServerHandler; + } + + @PostConstruct + public void start() { + EventLoopGroup bossGroup = new NioEventLoopGroup(); + EventLoopGroup workerGroup = new NioEventLoopGroup(); + try { + ServerBootstrap serverBootstrap = new ServerBootstrap(); + serverBootstrap.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .childHandler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) { + ch.pipeline().addLast(new HttpServerCodec()); + ch.pipeline().addLast(new ChunkedWriteHandler()); + ch.pipeline().addLast(new HttpObjectAggregator(8192)); + // WebSocket协议处理器 + ch.pipeline().addLast(new WebSocketServerProtocolHandler("/ws")); + ch.pipeline().addLast(new WebSocketServerHandler()); + } + }) + .option(ChannelOption.SO_BACKLOG, 128) + .childOption(ChannelOption.SO_KEEPALIVE, true); + + ChannelFuture channelFuture = serverBootstrap.bind(port).sync(); + System.out.println("WebSocket Server started on port: " + port); + channelFuture.channel().closeFuture().sync(); + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + bossGroup.shutdownGracefully(); + workerGroup.shutdownGracefully(); + } + } +} diff --git a/src/main/java/com/example/demo/Service/WebSocketServerHandler.java b/src/main/java/com/example/demo/Service/WebSocketServerHandler.java new file mode 100644 index 0000000..d88b0de --- /dev/null +++ b/src/main/java/com/example/demo/Service/WebSocketServerHandler.java @@ -0,0 +1,48 @@ +package com.example.demo.Service; + +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.handler.codec.http.websocketx.WebSocketServerHandshaker; +import io.netty.util.concurrent.GlobalEventExecutor; +import org.springframework.stereotype.Component; + +@Component +public class WebSocketServerHandler extends SimpleChannelInboundHandler { + + // 管理所有连接的WebSocket通道 + private static final ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); + + private WebSocketServerHandshaker webSocketServerHandshaker; + @Override + public void handlerAdded(ChannelHandlerContext ctx) { + channels.add(ctx.channel()); + channels.writeAndFlush(new TextWebSocketFrame("[客户端] - " + ctx.channel().remoteAddress() + " 加入聊天室")); + } + + @Override + public void handlerRemoved(ChannelHandlerContext ctx) { + channels.remove(ctx.channel()); + channels.writeAndFlush(new TextWebSocketFrame("[客户端] - " + ctx.channel().remoteAddress() + " 离开聊天室")); + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) { + // 广播消息到所有客户端 + channels.forEach(ch -> { + if (ch != ctx.channel()) { + ch.writeAndFlush(new TextWebSocketFrame("[客户端] " + ctx.channel().remoteAddress() + " 说:" + msg.text())); + } else { + ch.writeAndFlush(new TextWebSocketFrame("[你] 说:" + msg.text())); + } + }); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + cause.printStackTrace(); + ctx.close(); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index c1131e3..eca3a1c 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -14,3 +14,5 @@ spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect #??mapper xml??? mybatis-plus.mapper-locations=classpath:mappers/*.xml + +netty.port=8080