🎨 项目十:多种协议消息类型通信处理
项目概述
项目名称:itstack-demo-netty-2-10
核心功能:实现接收和发送多种协议消息类型的通信处理方案
技术要点:抽象类设计、工厂模式、策略模式、消息路由
为什么需要这个项目?
实际问题:
- 实际应用中需要处理多种消息类型(登录、聊天、退出等)
- 使用if-else判断消息类型,代码臃肿难维护
- 新增消息类型需要修改现有代码,违反开闭原则
- 缺少统一的消息处理框架
解决方案:
- ✅ 抽象类设计:统一消息基类,规范消息结构
- ✅ 工厂模式:根据指令自动创建对应的消息对象
- ✅ 策略模式:每种消息类型对应一个Handler
- ✅ 泛型路由:Netty自动根据泛型路由到对应Handler
适用场景:
- IM系统(登录、聊天、群聊、文件传输等多种消息)
- 游戏服务器(移动、攻击、交易等多种协议包)
- 物联网平台(多种设备协议)
- 复杂的业务系统(需要处理多种请求类型)
核心问题
为什么需要多协议支持?
在实际应用中(如聊天室),客户端与服务端需要发送多种消息类型:
- 登录验证
- 组建群聊
- 发送消息
- 退出登录
如果使用统一对象+if判断来分别转换,维护成本会非常大,不符合面向对象的设计思想。
传统方式的问题:
// ❌ 不好的设计
if (msgType == 1) {
// 处理登录
} else if (msgType == 2) {
// 处理群聊
} else if (msgType == 3) {
// 处理消息
}
// 新增消息类型需要修改这里,违反开闭原则
核心知识点
1. 协议设计层
Packet.java - 抽象基类
public abstract class Packet {
/**
* 获取协议指令
* @return 返回指令值
*/
public abstract Byte getCommand();
}
Command.java - 指令常量
public interface Command {
Byte Demo01 = 1; // 测试01
Byte Demo02 = 2; // 测试02
Byte Demo03 = 3; // 测试03
}
PacketClazzMap.java - 指令与类的映射
public class PacketClazzMap {
public final static Map<Byte, Class<? extends Packet>> packetTypeMap =
new ConcurrentHashMap<>();
static {
packetTypeMap.put(Command.Demo01, MsgDemo01.class);
packetTypeMap.put(Command.Demo02, MsgDemo02.class);
packetTypeMap.put(Command.Demo03, MsgDemo03.class);
}
}
2. 消息实体设计
MsgDemo01.java
public class MsgDemo01 extends Packet {
private String channelId;
private String demo01;
@Override
public Byte getCommand() {
return Command.Demo01; // 返回唯一标识
}
}
3. 编解码器实现
ObjEncoder.java - 编码器
public class ObjEncoder extends MessageToByteEncoder<Packet> {
@Override
protected void encode(ChannelHandlerContext ctx, Packet in, ByteBuf out) {
byte[] data = SerializationUtil.serialize(in);
out.writeInt(data.length + 1); // 长度(数据+指令)
out.writeByte(in.getCommand()); // 指令标识 ⭐
out.writeBytes(data); // 序列化数据
}
}
数据格式:
[4字节长度][1字节指令][N字节数据]
ObjDecoder.java - 解码器
public class ObjDecoder extends ByteToMessageDecoder {
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
// 1. 读取长度
int dataLength = in.readInt();
// 2. 读取指令
byte command = in.readByte();
// 3. 读取数据
byte[] data = new byte[dataLength - 1];
in.readBytes(data);
// 4. 根据指令找到对应的类,反序列化 ⭐
out.add(SerializationUtil.deserialize(data,
PacketClazzMap.packetTypeMap.get(command)));
}
}
4. 消息处理器
MsgDemo01Handler.java
public class MsgDemo01Handler extends SimpleChannelInboundHandler<MsgDemo01> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, MsgDemo01 msg) {
// 只处理MsgDemo01类型的消息
System.out.println("消息内容:" + msg.getDemo01());
}
}
关键点:SimpleChannelInboundHandler<MsgDemo01> 使用泛型,Netty会自动路由!
5. Pipeline配置
protected void initChannel(SocketChannel channel) {
channel.pipeline().addLast(new ObjDecoder()); // 解码
channel.pipeline().addLast(new MsgDemo01Handler()); // 处理消息1
channel.pipeline().addLast(new MsgDemo02Handler()); // 处理消息2
channel.pipeline().addLast(new MsgDemo03Handler()); // 处理消息3
channel.pipeline().addLast(new ObjEncoder()); // 编码
}
完整流程
客户端发送MsgDemo01对象
↓
ObjEncoder编码:
- 序列化对象 → byte[]
- 添加长度字段
- 添加指令字段(Command.Demo01 = 1)
↓
网络传输:[长度][指令1][数据]
↓
服务端ObjDecoder解码:
- 读取指令 = 1
- 从PacketClazzMap找到 MsgDemo01.class
- 反序列化为MsgDemo01对象
↓
Netty根据泛型路由到MsgDemo01Handler
↓
MsgDemo01Handler处理消息
项目总结
核心设计模式:
- ✅ 策略模式:不同消息类型 = 不同策略
- ✅ 工厂模式:PacketClazzMap充当工厂
- ✅ 泛型+多态:自动路由消息
架构优势:
- 新增消息类型只需:
- 创建新的消息类(继承Packet)
- 定义新的指令常量
- 在PacketClazzMap注册
- 创建对应的Handler
- 在Pipeline中添加Handler
- 无需修改现有代码!(开闭原则)
适用场景:
- IM系统(多种消息类型)
- 游戏服务器(多种协议包)
- 物联网平台(多种设备协议)
2642



被折叠的 条评论
为什么被折叠?



