基于Netty构建WebSocket服务器实战指南

一、WebSocket服务器基础概念

1.1 WebSocket简介

WebSocket是一种在单个TCP连接上进行全双工通信的协议,允许服务端主动向客户端推送数据,解决了HTTP协议只能由客户端发起请求的问题。

1.2 Netty框架优势

  • 高性能:基于NIO的异步事件驱动模型
  • 可扩展性:灵活的管道机制,易于扩展
  • 成熟稳定:被广泛应用在各种高并发场景

二、核心代码解析

2.1 服务器初始化

java 复制代码
@PostConstruct
public void init() {
    new Thread(() -> {
        try {
            start();
        } catch (InterruptedException e) {
            log.error("启动WebSocket服务器失败!", e);
        }
    }).start();
}

使用@PostConstruct注解确保Spring容器初始化完成后自动启动WebSocket服务器。

2.2 线程组配置

java 复制代码
// 主线程组:处理客户端连接
EventLoopGroup bossGroup = new NioEventLoopGroup();
// 工作线程组:处理连接后的I/O操作
EventLoopGroup workGroup = new NioEventLoopGroup();
  • bossGroup:负责接受新连接
  • workGroup:负责处理已建立连接的I/O操作

2.3 ChannelPipeline配置

java 复制代码
pipeline.addLast(new HttpServerCodec());           // HTTP编解码器
pipeline.addLast(new HttpObjectAggregator(65535)); // HTTP消息聚合器
pipeline.addLast(new WebSocketServerProtocolHandler("/testWs")); // WebSocket协议处理器

三、实际应用案例

3.1 场景:实时聊天室

案例背景

假设我们需要构建一个简单的实时聊天室,用户可以加入聊天室并实时接收其他用户发送的消息。

服务器端实现要点
  • 使用ChannelGroup管理所有连接的客户端
  • handlerAdded()方法中添加新连接到群组
  • handlerRemoved()方法中移除断开的连接
客户端HTML示例
html 复制代码
<!DOCTYPE html>
<html>
<head>
    <title>WebSocket聊天室</title>
</head>
<body>
    <div id="messages"></div>
    <input type="text" id="messageInput" placeholder="输入消息...">
    <button onclick="sendMessage()">发送</button>

    <script>
        const ws = new WebSocket('ws://localhost:9090/testWs');
        
        ws.onopen = function(event) {
            console.log('连接已建立');
        };
        
        ws.onmessage = function(event) {
            const messages = document.getElementById('messages');
            messages.innerHTML += '<p>' + event.data + '</p>';
        };
        
        function sendMessage() {
            const input = document.getElementById('messageInput');
            ws.send(input.value);
            input.value = '';
        }
    </script>
</body>
</html>

3.2 消息处理逻辑

java 复制代码
@Override
protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) {
    Channel channel = ctx.channel();
    log.info("收到来自通道channelId[{}]发送的消息:{}", channel.id(), msg.text());

    // 回复确认消息给发送者
    ctx.writeAndFlush(new TextWebSocketFrame("收到您的消息:" + msg.text()));

    // 广播消息给其他所有客户端(注释部分)
    // channelGroup.writeAndFlush(new TextWebSocketFrame("来自[" + channel.id() + "]的消息:" + msg.text()));
}

四、功能特性说明

4.1 连接管理

  • 连接建立 :通过handlerAdded()捕获新连接并添加到ChannelGroup
  • 连接断开 :通过handlerRemoved()清理断开的连接
  • 连接监控:记录连接状态变化日志

4.2 消息处理

  • 单播:只回复给发送消息的客户端
  • 广播:可以向所有连接的客户端发送消息(需取消注释相关代码)

4.3 错误处理

  • 异常捕获:在init()方法中捕获InterruptedException
  • 日志记录:详细记录连接状态和消息处理过程

五、部署与测试

5.1 启动服务

  • Spring Boot应用启动后会自动初始化WebSocket服务器
  • 服务器监听端口:9090
  • WebSocket路径:/testWs

5.2 测试验证

  1. 打开多个浏览器窗口访问客户端页面
  2. 在任意窗口发送消息
  3. 观察其他窗口是否能收到对应消息
  4. 查看控制台日志验证连接状态

六、优化建议

6.1 性能优化

  • 根据服务器性能调整NioEventLoopGroup线程数
  • 合理设置消息聚合器大小
  • 实现心跳机制防止连接超时

6.2 安全考虑

  • 添加身份验证机制
  • 实现消息过滤和防攻击机制
  • 考虑使用WSS(WebSocket Secure)协议

这个WebSocket服务器为实时通信提供了坚实的基础架构,可根据具体业务需求进行定制化开发。

java 复制代码
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
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.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

/**
 * WebSocket服务器类
 */
@Getter
@Slf4j
@Component
public class WebSocketServer {

    // 管理所有WebSocket连接的通道组
    private final ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    @PostConstruct
    public void init() {
        new Thread(() -> {
            try {
                start();
            } catch (InterruptedException e) {
                log.error("启动WebSocket服务器失败!", e);
            }

        }).start();
    }

    /**
     * 启动WebSocket服务器
     */
    public void start() throws InterruptedException {
        // 主线程组:处理客户端连接
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        // 工作线程组:处理连接后的I/O操作
        EventLoopGroup workGroup = new NioEventLoopGroup();

        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(bossGroup, workGroup);
        serverBootstrap.channel(NioServerSocketChannel.class);
        serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {

            @Override
            protected void initChannel(SocketChannel socketChannel) {
                ChannelPipeline pipeline = socketChannel.pipeline();
                // HTTP编解码器
                pipeline.addLast(new HttpServerCodec());
                // HTTP消息聚合器
                pipeline.addLast(new HttpObjectAggregator(65535));
                // WebSocket协议处理器,路径为/testWs
                pipeline.addLast(new WebSocketServerProtocolHandler("/testWs"));

                // 自定义业务处理器
                pipeline.addLast(new SimpleChannelInboundHandler<TextWebSocketFrame>() {

                    @Override
                    public void handlerAdded(ChannelHandlerContext ctx) {
                        // 客户端连接建立
                        Channel channel = ctx.channel();
                        log.info("客户端 建立连接:channelId={}", channel.id());
                        channelGroup.add(channel);
                    }

                    @Override
                    public void handlerRemoved(ChannelHandlerContext ctx) {
                        // 客户端连接断开
                        Channel channel = ctx.channel();
                        log.info("客户端 断开连接:channelId={}", channel.id());
                        channelGroup.remove(channel);
                    }

                    @Override
                    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) {
                        // 处理收到的文本消息
                        Channel channel = ctx.channel();
                        log.info("收到来自通道channelId[{}]发送的消息:{}", channel.id(), msg.text());

                        // 回复消息给发送者
                        ctx.writeAndFlush(new TextWebSocketFrame("收到您的消息:" + msg.text()));

                        // 广播消息给所有客户端
                        //channelGroup.writeAndFlush( new TextWebSocketFrame("收到来自通道channelId[" + channel.id() + "]发送的消息:" + msg.text()));
                    }
                });
            }
        });

        // 绑定端口并启动服务器
        ChannelFuture channelFuture = serverBootstrap.bind(9090).sync();
        log.info("Server started and listen on:{}", channelFuture.channel().localAddress());
        // 等待服务器关闭
        channelFuture.channel().closeFuture().sync();
    }
}

客户端连接地址 ws://127.0.0.1:9090/testWs

6.3 调试

推荐一个WebSocke在线网站

https://webfem.com/tools/ws/index.html

七、总结

基于Netty框架构建的WebSocket服务器,实现了完整的实时通信功能。
核心技术 :采用Netty的NioEventLoopGroup线程模型,通过ChannelGroup管理连接池
协议处理 :配置HTTP编解码器和WebSocket协议处理器,路径为/testWs
功能特性 :支持连接建立/断开监控、单播回复和广播消息、详细日志记录
部署运行:自动随Spring Boot启动,监听端口9090,适用于聊天室、消息推送等实时交互场景

相关推荐
GeekyGuru3 小时前
TCP/IP协议栈深度解析:从分层原理到内核实现与调优
网络·网络协议·tcp/ip
凯子坚持 c3 小时前
Protocol Buffers C++ 进阶数据类型与应用逻辑深度解析
java·服务器·c++
宴之敖者、4 小时前
Linux——权限
linux·运维·服务器
txinyu的博客4 小时前
MAC 地址
服务器·网络·macos
我爱娃哈哈4 小时前
SpringBoot + Spring Security + RBAC:企业级权限模型设计与动态菜单渲染实战
spring boot·后端·spring
科技块儿5 小时前
【场景:识别C2通信】评估出站IP是否为已知恶意地址,方法:IP离线库+威胁情报融合
网络·网络协议·tcp/ip
咕噜签名-铁蛋6 小时前
火山云豆包:重新定义AI交互,让智能触手可及
服务器
小王不爱笑1326 小时前
SpringBoot 配置文件
java·spring boot·后端
安当加密6 小时前
电力系统如何防“明文传输”?某电网公司用SM2+UKey构建“端到端加密”实战
服务器·数据库·安全·阿里云