bash
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.50.Final</version>
</dependency>
@SpringBootApplication
public class RouteDefenseApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(RouteDefenseApplication.class, args);
System.out.println("启动成功!");
}
@Autowired
private NettyServer nettyServer;
@Override
public void run(String... args) throws Exception {
new Thread(nettyServer).start();
}
}
bash
@Component
public class NettyServer implements Runnable{
public void start(InetSocketAddress address) {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup group = new NioEventLoopGroup();
try {
ServerBootstrap sb = new ServerBootstrap();
sb.option(ChannelOption.SO_BACKLOG, 1024);
sb.group(group, bossGroup) // 绑定线程池
.channel(NioServerSocketChannel.class) // 指定使用的channel
.localAddress(address)// 绑定监听端口
.childHandler(new ChannelInitializer<SocketChannel>() { // 绑定客户端连接时候触发操作
@Override
protected void initChannel(SocketChannel ch) throws Exception {
//websocket协议本身是基于http协议的,所以这边也要使用http解编码器
ch.pipeline().addLast(new HttpServerCodec());
//以块的方式来写的处理器
ch.pipeline().addLast(new ChunkedWriteHandler());
ch.pipeline().addLast(new HttpObjectAggregator(8192));
ch.pipeline().addLast(new WebSocketServerProtocolHandler("/ws", "WebSocket", true, 65536 * 10));
ch.pipeline().addLast(new MyWebSocketHandler());//自定义消息处理类
}
});
ChannelFuture cf = sb.bind(address).sync(); // 服务器异步创建绑定
System.out.println(NettyServer.class + "已启动,正在监听: " + cf.channel().localAddress());
cf.channel().closeFuture().sync(); // 关闭服务器通道
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
try {
group.shutdownGracefully().sync(); // 释放线程池资源
bossGroup.shutdownGracefully().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Override
public void run() {
InetSocketAddress address = new InetSocketAddress(10007);
this.start(address);
}
}
bash
public class MyWebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
private static final Logger logger = LoggerFactory.getLogger(MyWebSocketHandler.class);
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("与客户端建立连接,通道开启!");
//添加到channelGroup通道组
MyChannelHandlerPool.channelGroup.add(ctx.channel());
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("与客户端断开连接,通道关闭!");
//从channelGroup通道组删除
MyChannelHandlerPool.channelGroup.remove(ctx.channel());
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
//接收的消息
System.out.println(String.format("收到客户端%s的数据:%s" ,ctx.channel().id(), msg.text()));
// 单独发消息
// sendMessage(ctx);
// 群发消息
sendAllMessage();
}
private void sendMessage(ChannelHandlerContext ctx){
String message = "消息";
ctx.writeAndFlush(new TextWebSocketFrame(message));
}
private void sendAllMessage(){
String message = "我是服务器,这是群发消息";
MyChannelHandlerPool.channelGroup.writeAndFlush(new TextWebSocketFrame(message));
}
}
bash
public class MyChannelHandlerPool {
public MyChannelHandlerPool() {
}
//可以存储userId与ChannelId的映射表
public static ConcurrentHashMap<String, ChannelId> channelIdMap = new ConcurrentHashMap<>();
//channelGroup通道组
public static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
}
发送消息:
bash
MyChannelHandlerPool.channelGroup.writeAndFlush("我是后端消息!!!!!");