[一、 Netty网络框架、WebSocket协议基础](#一、 Netty网络框架、WebSocket协议基础)
[1.1 Netty网络框架介绍](#1.1 Netty网络框架介绍)
[1.2 WebSocket简介](#1.2 WebSocket简介)
[1.3 WebSocket握手流程](#1.3 WebSocket握手流程)
[三、Netty+WebSocket与Spring WebSocket](#三、Netty+WebSocket与Spring WebSocket)
[3.1 架构层级对比](#3.1 架构层级对比)
[3.2 核心组件差异](#3.2 核心组件差异)
[3.3 协议支持深度](#3.3 协议支持深度)
[3.4 性能基准测试](#3.4 性能基准测试)
[3.5 开发效率对比](#3.5 开发效率对比)
[3.6 典型应用场景](#3.6 典型应用场景)
[3.7 集成生态对比编辑](#3.7 集成生态对比编辑)
四、基于Netty+WebSocket构建高性能实时通信系统
[4.1 技术选型](#4.1 技术选型)
[4.2 pom.xml核心依赖](#4.2 pom.xml核心依赖)
[4.3 Netty服务的启动类(服务器)](#4.3 Netty服务的启动类(服务器))
[4.4 WebSocket初始化器](#4.4 WebSocket初始化器)
[4.5 心跳处理类](#4.5 心跳处理类)
[4.6 消息处理器](#4.6 消息处理器)
[4.7 Vue2 WebSocket连接核心代码](#4.7 Vue2 WebSocket连接核心代码)
一、 Netty网络框架、WebSocket协议基础
1.1 Netty网络框架介绍
参考我的另一篇文章:
1.2 WebSocket简介
WebSocket是一种在单个TCP连接上进行全双工通信的协议,解决了HTTP协议的半双工和轮询效率低的问题。其核心特点:
全双工:客户端和服务端可同时发送数据。
持久连接:一次握手后保持长连接。
低延迟:无需频繁建立连接。
1.3 WebSocket握手流程
客户端发起HTTP请求:包含Upgrade:websocket头。
服务端响应101状态码:表示协议切换成功。
数据帧传输:后续通信通过二进制帧(Frame)进行。
握手请求示例:
html
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Version: 13
握手响应示例:
html
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
二、为什么选择Netty+WebSocket?
在实时通信(IM)场景中,低延迟、高并发、长连接是核心需求。Netty作为高性能网络框架,结合WebSocket协议,能够完美满足这些要求:
全双工通信:WebSocket支持服务端主动推送,告别HTTP轮询
低延迟:Netty的Reactor线程模型+零拷贝技术,轻松支撑10万级并发
协议灵活:可扩展支持自定义二进制协议
本文将带你从零开始 实现一个完整的IM系统,涵盖消息收发、用户在线状态管理、心跳检测 等核心功能,并提供可运行的完整代码。
三、Netty+WebSocket与Spring WebSocket
3.1 架构层级对比

3.2 核心组件差异
Netty核心模块
java
// 典型Netty WebSocket配置
pipeline.addLast(new HttpServerCodec()); // HTTP编解码
pipeline.addLast(new HttpObjectAggregator(65536)); // 聚合HTTP请求
pipeline.addLast(new WebSocketServerProtocolHandler("/ws")); // 协议升级
pipeline.addLast(new CustomFrameHandler()); // 自定义业务处理
Spring核心模块
java
// 典型Spring配置
@Configuration
@EnableWebSocket
public class Config implements WebSocketConfigurer {
void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myHandler(), "/ws");
}
}
3.3 协议支持深度

3.4 性能基准测试

3.5 开发效率对比

3.6 典型应用场景
Netty更适合:
游戏服务器(需要自定义二进制协议)
金融级交易系统(微秒级延迟要求)
IoT设备接入(海量长连接管理)
Spring WebSocket更适合:
企业级消息通知系统
实时协作应用(如在线文档)
需要快速集成Spring Security的场景
3.7 集成生态对比
四、基于Netty+WebSocket构建高性能实时通信系统
4.1 技术选型
Java 8+、Netty 4.x、WebSocket协议、Maven
4.2pom.xml核心依赖
XML
<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.86.Final</version>
</dependency>
</dependencies>
4.3 Netty服务的启动类(服务器)
java
/**
* ChatServer: Netty 服务的启动类(服务器)
*/
public class ChatServer {
public static void main(String[] args) throws Exception {
// 定义主从线程组
// 定义主线程池,用于接受客户端的连接,但是不做任何处理,比如老板会谈业务,拉到业务就会交给下面的员工去做了
EventLoopGroup bossGroup = new NioEventLoopGroup();
// 定义从线程池,处理主线程池交过来的任务,公司业务员开展业务,完成老板交代的任务
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
// 构建Netty服务器
ServerBootstrap server = new ServerBootstrap(); // 服务的启动类
server.group(bossGroup, workerGroup) // 把主从线程池组放入到启动类中
.channel(NioServerSocketChannel.class) // 设置Nio的双向通道
.childHandler(new WSServerInitializer()); // 设置处理器,用于处理workerGroup
// 启动server,并且绑定端口号875,同时启动方式为"同步"
ChannelFuture channelFuture = server.bind(875).sync();
// 请求:http://127.0.0.1:875
// 监听关闭的channel
channelFuture.channel().closeFuture().sync();
} finally {
// 优雅的关闭线程池组
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
4.4 WebSocket初始化器
java
/**
* 初始化器,channel注册后,会执行里面的相应的初始化方法
*/
public class WSServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel channel) throws Exception {
// 通过SocketChannel获得对应的管道
ChannelPipeline pipeline = channel.pipeline();
/**
* 通过管道,添加handler处理器
*/
// HttpServerCodec 是由netty自己提供的助手类,此处可以理解为管道中的拦截器
// 当请求到服务端,我们需要进行做解码,相应到客户端做编码
// websocket 基于http协议,所以需要有http的编解码器
pipeline.addLast(new HttpServerCodec());
// 添加对大数据流的支持
pipeline.addLast(new ChunkedWriteHandler());
// 对httpMessage进行聚合,聚合成为FullHttpRequest或FullHttpResponse
// 几乎在netty的编程中,都会使用到此handler
pipeline.addLast(new HttpObjectAggregator(1024 * 64));
// ==================== 以上是用于支持http协议相关的handler ====================
// ==================== 增加心跳支持 start ====================
// 针对客户端,如果在5小时没有向服务端发送读写心跳(ALL),则主动断开连接
// 如果是读空闲或者写空间,不做任何处理(参数分别对应读空闲、写空闲、读写空闲秒数)
pipeline.addLast(new IdleStateHandler(
8,
10,
300 * 60));
pipeline.addLast(new HeartBeatHandler());
// ==================== 增加心跳支持 end ====================
// ==================== 以下是用于支持websocket ====================
/**
* WebSocket 服务器处理的协议,用于指定给客户端连接的时候访问路由: /ws
* 此Handler会帮我们处理一些比较复杂的繁重的操作
* 会处理一些握手操作:handShaking(close,ping,pong)ping + pong = 心跳
* 对于WebSocket来说,数据都是以frames(帧)进行传输的,不同的数据类型所对应的frames(帧)也都不同
*/
pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
// 添加自定义的助手类
pipeline.addLast(new ChatHandler());
}
}
4.5 心跳处理类
java
/**
* 创建心跳助手类
*/
public class HeartBeatHandler extends ChannelInboundHandlerAdapter {
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
// 判断evt是否是IdleStateEvent(空闲事件状态,包含 读空闲/写空闲/读写空闲)
if (evt instanceof IdleStateEvent) {
IdleStateEvent event = (IdleStateEvent)evt;
if (event.state() == IdleState.READER_IDLE) {
// System.out.println("进入读空闲...");
} else if (event.state() == IdleState.WRITER_IDLE) {
// System.out.println("进入写空闲...");
} else if (event.state() == IdleState.ALL_IDLE) {
Channel channel = ctx.channel();
// 关闭无用的channel,以防资源浪费
channel.close();
}
}
}
}
4.6 消息处理器
java
/**
* 创建自定义助手类
*/
// SimpleChannelInboundHandler: 对于请求来说,相当于入站(入境)
// TextWebSocketFrame: 用于为websocket专门处理的文本数据对象,Frame是数据(消息)的载体
public class ChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
// 存储所有连接的Channel
private static final ChannelGroup clients =
new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
@Override
public void channelActive(ChannelHandlerContext ctx) {
clients.add(ctx.channel());
System.out.println("客户端连接: " + ctx.channel().id());
}
@Override
public void channelInactive(ChannelHandlerContext ctx) {
clients.remove(ctx.channel());
System.out.println("客户端断开: " + ctx.channel().id());
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame frame) {
String msg = frame.text();
System.out.println("收到消息: " + msg);
// 方案1:广播给所有客户端
clients.writeAndFlush(new TextWebSocketFrame("[广播] " + msg));
// 方案2:转发给特定客户端(示例逻辑)
if (msg.startsWith("@")) {
forwardToTargetClient(msg);
}
}
private void forwardToTargetClient(String msg) {
String targetId = msg.substring(1, msg.indexOf(" "));
String content = msg.substring(msg.indexOf(" ") + 1);
clients.stream()
.filter(ch -> ch.id().asShortText().equals(targetId))
.findFirst()
.ifPresent(ch ->
ch.writeAndFlush(new TextWebSocketFrame("[私信] " + content))
);
}
/**
* 发生异常并且捕获,移除channel
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
clients.remove(ctx.channel());
ctx.close();
cause.printStackTrace();
}
}
4.7 Vue2 WebSocket连接核心代码
javascript
// src/utils/websocket.js
export default class SocketService {
static instance = null
static get Instance() {
if (!this.instance) {
this.instance = new SocketService()
}
return this.instance
}
// 连接状态标记
connected = false
ws = null
// 初始化连接
connect() {
if (!this.connected) {
this.ws = new WebSocket('ws://localhost:875')
this.ws.onopen = () => {
this.connected = true
console.log('Netty连接成功')
}
this.ws.onmessage = (msg) => {
console.log('收到消息:', msg.data)
// 这里可以触发Vuex的action处理消息
}
this.ws.onclose = () => {
this.connected = false
console.log('Netty连接关闭')
}
this.ws.onerror = (err) => {
console.error('连接错误:', err)
}
}
}
// 发送消息
send(data) {
if (this.connected) {
this.ws.send(JSON.stringify(data))
} else {
console.error('尚未建立连接')
}
}
}
html
<template>
<div>
<button @click="connect">连接Netty</button>
<button @click="sendTestMsg">发送测试消息</button>
<div v-for="(msg, index) in messages" :key="index">
{{ msg }}
</div>
</div>
</template>
<script>
import SocketService from '@/utils/websocket'
export default {
data() {
return {
messages: []
}
},
methods: {
connect() {
SocketService.Instance.connect()
},
sendTestMsg() {
SocketService.Instance.send({
type: 'test',
content: 'Hello Netty!',
timestamp: Date.now()
})
}
},
mounted() {
// 可选:组件加载时自动连接
// this.connect()
}
}
</script>
4.8 Spring WebSocket实现简单通信系统
参考我的文章: 【Spring WebSocket详解】Spring WebSocket从入门到实战-CSDN博客
五、总结
本文通过Netty框架实现了基于WebSocket协议的简单通信系统,覆盖了从基础握手、消息处理到心跳检测的全流程。实际开发中还需考虑安全性(如WSS加密)、跨域处理、消息持久化等高级功能。如果你对上文有什么其他理解或者问题欢迎评论区留言讨论!