單一 `readLine()` 循環無法區分「語音/視頻/圖片/數據」等異構請求,且無法實現服務端主動推送。
// 1. 協議定義 (JSON 示例)
{
"cmd": "LOGIN", // 命令字
"seq": 1001, // 請求序列號
"payload": { ... } // 業務負載
}
| 層級 | 組件 | 職責 |
|---|---|---|
| 傳輸層 | NioEventLoopGroup | 網絡 I/O 事件循環 |
| 協議層 | LengthFieldBasedFrameDecoder + JsonDecoder/Encoder | 半包/粘包處理、序列化 |
| 業務層 | CommandHandler 命令分發器 | 根據 cmd 路由到具體 Handler |
| 會話層 | ChannelGroup / AttributeKey | 管理在線用戶、群組、心跳 |
// 命令分發器
public class CommandDispatcher extends SimpleChannelInboundHandler {
private final Map handlers = new ConcurrentHashMap<>();
public void register(String cmd, CommandHandler handler) {
handlers.put(cmd, handler);
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, ProtocolMessage msg) {
CommandHandler handler = handlers.get(msg.getCmd());
if (handler != null) {
handler.handle(ctx, msg);
} else {
log.warn("未知命令: {}", msg.getCmd());
}
}
}
// 具體業務 Handler
public class VoiceHandler implements CommandHandler {
@Override
public void handle(ChannelHandlerContext ctx, ProtocolMessage msg) {
// 處理語音幀,轉發給目標用戶/群組
SessionManager.forwardToGroup(msg.getGroupId(), msg);
}
}
// 主動推送:服務端任意位置調用
public class NotificationService {
public void pushLocationUpdate(String groupId, Location loc) {
ProtocolMessage msg = ProtocolMessage.builder()
.cmd("LOCATION_UPDATE")
.payload(loc)
.build();
SessionManager.getGroupChannels(groupId).writeAndFlush(msg);
}
}