ConChat 实时聊天室

体验地址:http://141.11.62.140:5173/
预览:

file

file

file

Socket.IO实时通信架构

技术难点

Socket.IO作为一种复杂的实时通信解决方案,在项目中实现了多种通信模式:

  • 同时维护大量客户端连接
  • 高效处理不同类型的消息事件
  • 实现可靠的消息传递与确认机制
  • 处理网络波动和断线重连

实现方式

项目通过组织良好的事件处理系统实现了复杂的实时通信:

// 配置Socket.IO服务器参数确保稳定连接
@Bean
public SocketIOServer socketIOServer() {
    Configuration config = new Configuration();
    config.setPort(socketService.getPort());
    config.setOrigin(socketService.getOrigin());
    config.setHostname(socketService.getHost());
    config.setPingTimeout(socketService.getPingTimeout());
    config.setPingInterval(socketService.getPingInterval());
    config.setUpgradeTimeout(socketService.getUpgradeTimeout());

    SocketIOServer socketIOServer = new SocketIOServer(config);
    // ...事件监听器配置
    return socketIOServer;
}

事件监听器模式设计使得系统可以灵活处理各类事件:

// 各种事件监听器组织
private Map<String, Object> createListenersMap() {
    Map<String, Object> listeners = new HashMap<>();
    listeners.put("sendListener", sendListener);
    listeners.put("editListener", editListener);
    listeners.put("userListener", userListener);
    listeners.put("adminListener", adminListener);
    // ...更多监听器
    return listeners;
}

分层的消息处理架构

技术难点

  • 如何将复杂的消息逻辑拆分为可维护的组件
  • 如何确保消息处理的一致性和可追踪性
  • 如何优化消息发送与存储

实现方式

项目通过精心设计的分层架构来处理消息:

// SendHandler.java - 处理发送消息的核心逻辑
public void handleSendMessage(SocketIOServer server, SocketIOClient client, 
                              Map<String, Object> data, AckRequest ackRequest) {
    // 1. 安全性检查
    if (!cacheService.validRedisMessageCache(clientService.getRemoteUID(client))) {
        ackRequest.sendAckData(new HandleResults().handleResultByCode(402, null, "操作频率过快"));
        return;
    }

    // 2. 用户状态检查
    if (!orUserService.getUserInnerStatus(clientService.getRemoteUID(client))) {
        ackRequest.sendAckData(new HandleResults().handleResultByCode(402, null, "未查询到用户"));
        return;
    }

    // 3. 频道状态检查
    if (!orChanService.getChanOpenStatus(clientService.getRemoteGID(client))) {
        ackRequest.sendAckData(new HandleResults().handleResultByCode(402, null, "该频道未开启"));
        return;
    }

    // 4. 系统全局状态检查
    if (ouSystemService.getSystemKeyStatus("taboo") && !clientService.getIsAdmin(client)) {
        ackRequest.sendAckData(new HandleResults().handleResultByCode(402, null, "全频禁言开启中"));
        return;
    }

    // 5. 消息存储与广播
    try {
        String content = clientService.getClientData(data, CONTENT_KEY);
        OP_ChatService OPChatService = (OP_ChatService) service.get("chatService");
        Map<String, Object> result = OPChatService.insertChatMessage(
            clientService.getClientData(data, TYPE_KEY), 
            clientService.getRemoteUID(client), 
            clientService.getRemoteGID(client), 
            clientService.getRemoteAddress(client), 
            content);

        // 6. 响应与广播
        sendAckData(ackRequest, result);
        if (isSuccessResult(result)) 
            new MessageUtils().sendGlobalMessage(server, "[MESSAGE]", result.get("data"));
    } catch (Exception e) {
        handleException(e, ackRequest);
    }
}

基于功能模块的项目架构

技术难点

项目采用了功能模块而非传统三层架构的组织方式:

  • 如何划分功能模块的边界
  • 如何防止模块间过度耦合
  • 如何保持模块的内聚性

实现方式

项目按功能划分了多个模块,每个模块包含自己的MVC组件:

/admin    - 管理员相关功能
  /dao    - 数据访问对象
  /mod    - 数据模型
  /man    - 管理逻辑
  /service - 业务服务

/sockets  - Socket通信功能
  /dao    - 数据访问对象
  /mod    - 数据模型
  /man    - 管理逻辑
  /service - 业务服务

/websocket - WebSocket实现
  /handler - 事件处理器
  /listener - 事件监听器
  /eventer - 事件分发器

这种架构在实际操作层面带来很多好处:

// OP_ChatService.java - 聊天服务类
@Service
public class OP_ChatService {
    private final OP_ChatDao opChatDao;
    // ...

    // 搜索聊天历史
    public OP_ChatModel searchHistoryById(String sid) {
        try {
            return opChatDao.selectOne(
                new QueryWrapper<OP_ChatModel>().eq("sid", sid));
        } catch (Exception e) {
            // 错误处理
        }
        return null;
    }

    // 插入聊天消息
    public Map<String, Object> insertChatMessage(String type, long uid, 
                                              long gid, String address, 
                                              String content) {
        try {
            OP_ChatModel OPChatModel = new OP_ChatModel();
            Map<String, Object> result = new OP_ChatManage()
                .insertChatMessage(OPChatModel, type, uid, gid, address, content);
            if (opChatDao.insert(OPChatModel) > 0) {
                return handleResults.handleResultByCode(200, result, "发送成功");
            } else return handleResults.handleResultByCode(400, null, "发送失败");
        } catch (Exception e) {
            // 错误处理
        }
    }
}

基于Redis的分布式缓存与防刷机制

技术难点

  • 高效处理用户状态和会话信息
  • 防止恶意用户刷屏和频繁操作
  • 确保系统在高并发下的稳定性

实现方式

项目使用Redis实现了消息缓存和频率控制:

// 消息频率限制检查
if (!cacheService.validRedisMessageCache(clientService.getRemoteUID(client))) {
    ackRequest.sendAckData(new HandleResults().handleResultByCode(402, null, "操作频率过快"));
    return;
}
// CacheService实现部分的核心逻辑
public boolean validRedisMessageCache(long uid) {
    String key = "message:limit:" + uid;
    // 检查是否在冷却时间内
    if (Boolean.TRUE.equals(template.hasKey(key))) {
        return false;
    }
    // 设置冷却时间
    template.opsForValue().set(key, "", COOL_DOWN_TIME, TimeUnit.MILLISECONDS);
    return true;
}

细粒度的权限控制系统

技术难点

  • 实现多层级的用户权限模型
  • 处理频道、管理员和系统全局权限
  • 动态调整权限状态

实现方式

项目实现了多层级的权限检查机制:

// 系统级全局禁言检查
if (ouSystemService.getSystemKeyStatus("taboo") && !clientService.getIsAdmin(client)) {
    ackRequest.sendAckData(new HandleResults().handleResultByCode(402, null, "全频禁言开启中"));
    return;
}

// 用户级禁言检查
if (orUserService.getUserTabooStatus(clientService.getRemoteUID(client)) && !clientService.getIsAdmin(client)) {
    ackRequest.sendAckData(new HandleResults().handleResultByCode(402, null, "你正在被禁言中"));
    return;
}

// 频道状态检查
if (!orChanService.getChanOpenStatus(clientService.getRemoteGID(client))) {
    ackRequest.sendAckData(new HandleResults().handleResultByCode(402, null, "该频道未开启"));
    return;
}

结构化的错误处理与响应机制

技术难点

  • 统一处理各类异常情况
  • 向客户端提供一致的错误信息
  • 方便的调试和故障追踪

实现方式

项目使用统一的结果处理机制:

// HandleResults类统一处理响应结果
public Map<String, Object> handleResultByCode(int code, Object data, String message) {
    Map<String, Object> result = new HashMap<>();
    result.put("code", code);
    result.put("data", data);
    result.put("message", message);
    return result;
}

// 错误处理和日志记录
private void handleException(Exception e, AckRequest ackRequest) {
    // 记录详细错误信息
    new ConsolePrints().printErrorLog(e);
    // 向客户端发送友好错误信息
    ackRequest.sendAckData(handleResults.handleResultByCode(500, null, "服务器异常"));
}
版权声明:除特殊说明,博客文章均为大块肌原创,依据CC BY-SA 4.0许可证进行授权,转载请附上出处链接及本声明。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇