本文目录导读:

下面为你提供一个基于 Netty 的即时通讯(IM)核心案例设计与代码实现,这个案例会涵盖客户端登录、单聊、群聊、心跳检测以及离线消息等核心功能。
系统架构设计
技术栈
- Netty 4.x — 网络通信框架
- Protobuf / JSON — 自定义协议(这里使用JSON简单演示,生产建议Protobuf)
- Redis — 用户路由信息存储(保证分布式集群状态一致性)
- MySQL + MyBatis — 好友关系与离线消息存储
核心模块划分
├── im-common // 公共模块:协议、常量、工具类
├── im-server // IM服务端
├── im-client // IM客户端(用于测试)
└── im-admin // 管理后台(可选)
自定义通信协议设计
由于Netty提供TCP传输,我们需要自定义消息边界,这里采用 长度域 + JSON体 方式:
// 消息结构:包体长度(4字节) + 消息类型(1字节) + 消息体(JSON)
协议定义(im-common模块)
public enum MsgType {
LOGIN_REQ(1), // 登录请求
LOGIN_RESP(2), // 登录响应
CHAT_MSG(3), // 聊天消息
PING(4), // 心跳
PONG(5); // 心跳响应
public final int code;
MsgType(int code) { this.code = code; }
public static MsgType fromCode(int code) {
for (MsgType type : values()) {
if (type.code == code) return type;
}
return null;
}
}
public class Message {
private MsgType type; // 消息类型
private String body; // JSON body
private long timestamp; // 客户端消息时间戳
// getter/setter...
}
服务端核心代码(im-server)
Netty服务端启动器
public class IMServer {
private EventLoopGroup bossGroup;
private EventLoopGroup workerGroup;
private Channel serverChannel;
public void start(int port) throws InterruptedException {
bossGroup = new NioEventLoopGroup(1);
workerGroup = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.childOption(ChannelOption.SO_KEEPALIVE, true)
.childOption(ChannelOption.TCP_NODELAY, true)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
ChannelPipeline pipeline = ch.pipeline();
// 拆包解包(处理半包/粘包)
pipeline.addLast(new LengthFieldBasedFrameDecoder(
1024*1024, 0, 4, 1, 0));
pipeline.addLast(new JsonDecoder());
// 写数据处理
pipeline.addLast(new JsonEncoder());
// 业务逻辑
pipeline.addLast(new IMServerHandler());
// **空闲检测:5分钟内无读则关闭**
pipeline.addLast(new IdleStateHandler(300, 0, 0));
pipeline.addLast(new HeartbeatHandler());
}
});
serverChannel = bootstrap.bind(port).sync().channel();
System.out.println("IM Server started on port " + port);
}
public void shutdown() {
if (serverChannel != null) serverChannel.close();
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
自定义编解码器
// JSON编码器
public class JsonEncoder extends MessageToByteEncoder<Message> {
private static final ObjectMapper mapper = new ObjectMapper();
@Override
protected void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) {
try {
byte[] data = mapper.writeValueAsBytes(msg);
out.writeInt(data.length); // 长度
out.writeByte(msg.getType().code); // 类型
out.writeBytes(data); // 数据
} catch (JsonProcessingException e) {
ctx.close();
}
}
}
// JSON解码器
public class JsonDecoder extends ByteToMessageDecoder {
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
// 因为前面已经使用LengthFieldBasedFrameDecoder拆包,这里直接解析
int len = in.readInt();
byte type = in.readByte();
byte[] body = new byte[len];
in.readBytes(body);
Message msg = new Message();
msg.setType(MsgType.fromCode(type));
msg.setBody(new String(body, StandardCharsets.UTF_8));
out.add(msg);
}
}
核心业务处理器
public class IMServerHandler extends SimpleChannelInboundHandler<Message> {
// 模拟在线用户表:userId -> Channel
public static ConcurrentHashMap<Long, Channel> onlineUsers = new ConcurrentHashMap<>();
@Override
public void channelActive(ChannelHandlerContext ctx) {
// 连接建立(尚未登录,此时不绑定用户)
System.out.println("新连接: " + ctx.channel().remoteAddress());
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, Message msg) {
switch (msg.getType()) {
case LOGIN_REQ:
handleLogin(ctx, msg);
break;
case CHAT_MSG:
handleChat(ctx, msg);
break;
case PING:
// 响应PONG(心跳处理)
Message pong = new Message();
pong.setType(MsgType.PONG);
ctx.writeAndFlush(pong);
break;
default:
ctx.close();
}
}
private void handleLogin(ChannelHandlerContext ctx, Message msg) {
// 解析登录请求
LoginRequest req = JSON.parseObject(msg.getBody(), LoginRequest.class);
// 模拟认证成功
// 1. 绑定用户ID与Channel
Long userId = req.getUserId();
onlineUsers.put(userId, ctx.channel());
// 2. 返回登录响应
Message resp = new Message();
resp.setType(MsgType.LOGIN_RESP);
resp.setBody("{\"code\":0,\"msg\":\"登录成功\"}");
ctx.writeAndFlush(resp);
System.out.println("用户 " + userId + " 登录成功");
}
private void handleChat(ChannelHandlerContext ctx, Message msg) {
ChatRequest req = JSON.parseObject(msg.getBody(), ChatRequest.class);
Long targetUserId = req.getTargetUserId();
// 单聊
if (req.getType() == 1) {
Channel targetChannel = onlineUsers.get(targetUserId);
if (targetChannel != null) {
// 构建发给目标的消息(添加发送者信息)
Message forward = new Message();
forward.setType(MsgType.CHAT_MSG);
forward.setBody(JSON.toJSONString(new ChatRequest(
req.getFromUserId(), req.getTargetUserId(), req.getContent())));
targetChannel.writeAndFlush(forward);
} else {
// 用户不在线,存离线消息(可存入Redis/MySQL)
saveOfflineMessage(req);
}
}
// 群聊逻辑类似:遍历群成员,逐个发送
}
@Override
public void channelInactive(ChannelHandlerContext ctx) {
// 移除在线用户
onlineUsers.entrySet().removeIf(entry -> entry.getValue() == ctx.channel());
System.out.println("连接关闭");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
心跳与超时处理器
public class HeartbeatHandler extends ChannelInboundHandlerAdapter {
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof IdleStateEvent) {
IdleStateEvent event = (IddStateEvent) evt;
if (event.state() == IdleState.READER_IDLE) {
// 5分钟没收到消息,判定死亡连接
System.out.println("心跳超时,关闭连接: " + ctx.channel().remoteAddress());
ctx.close();
}
} else {
super.userEventTriggered(ctx, evt);
}
}
}
客户端实现(im-client)
public class IMClient {
private Channel channel;
private Long userId;
public void connect(String host, int port) throws InterruptedException {
NioEventLoopGroup group = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(1024*1024, 0, 4, 1, 0));
ch.pipeline().addLast(new JsonDecoder());
ch.pipeline().addLast(new JsonEncoder());
ch.pipeline().addLast(new SimpleChannelInboundHandler<Message>() {
@Override
protected void channelRead0(ChannelHandlerContext, Message msg) {
// 处理服务端推送的消息
if (msg.getType() == MsgType.CHAT_MSG) {
ChatRequest req = JSON.parseObject(msg.getBody(), ChatRequest.class);
System.out.println("收到来自用户[" + req.getFromUserId() + "]: " + req.getContent());
}
}
});
}
});
channel = bootstrap.connect(host, port).sync().channel();
}
public void sendLogin(Long userId) {
this.userId = userId;
Message msg = new Message();
msg.setType(MsgType.LOGIN_REQ);
msg.setBody("{\"userId\":" + userId + "}");
channel.writeAndFlush(msg);
}
public void sendChat(Long targetUserId, String content) {
Message msg = new Message();
msg.setType(MsgType.CHAT_MSG);
msg.setBody(JSON.toJSONString(new ChatRequest(userId, targetUserId, content)));
channel.writeAndFlush(msg);
}
}
测试与运行
主测试类(两个客户端模拟单聊)
public class TestMain {
public static void main(String[] args) throws Exception {
// 启动服务端
new Thread(() -> {
try {
new IMServer().start(8080);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
Thread.sleep(1000);
// 客户端A登录
IMClient clientA = new IMClient();
clientA.connect("localhost", 8080);
clientA.sendLogin(1001L);
// 客户端B登录
IMClient clientB = new IMClient();
clientB.connect("localhost", 8080);
clientB.sendLogin(1002L);
Thread.sleep(500);
// A给B发送消息
clientA.sendChat(1002L, "你好,B!");
Thread.sleep(2000);
}
}
进阶与优化方向
- 协议优化:使用 Protobuf 代替JSON,性能提升数倍。
- 集群部署:接入 ZooKeeper 管理服务节点,通过 Redis Pub/Sub 实现跨节点消息转发。
- 消息可靠性:增加ACK确认机制,失败后自动重发。
- 离线消息:用户登录后拉取Redis/MySQL中的离线消息。
- 流量控制:结合Netty的高水位(WriteBufferWaterMark)实现背压。
- 安全:TLS/SSL加密,防止抓包。
技术要点总结
| 功能 | 实现方案 |
|---|---|
| 粘包/拆包 | LengthFieldBasedFrameDecoder 长度域拆包 |
| 心跳检测 | IdleStateHandler 定期检测读空闲 |
| 在线管理 | ConcurrentHashMap<userId, Channel> |
| 多端登录 | 使用Redis记录最新设备,踢出旧设备 |
| 消息有序 | 引入消息序号,配合Redis队列 |
| 性能调优 | 使用 NioEventLoopGroup,合理配置线程数 |
这个案例涵盖了Netty在IM系统中的核心流程和常见解决方案,你可以基于此框架扩展到更复杂的业务场景,群管理、朋友圈、文件传输等功能,核心在于处理好协议定义、连接管理和消息路由三大部分。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播