# go-chat **Repository Path**: coding_niann/go-chat ## Basic Information - **Project Name**: go-chat - **Description**: golang实现的聊天室系统 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-06-18 - **Last Updated**: 2025-06-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README 基于 Go 语言开发的一套支持私聊与群聊的即时通讯系统,采用 RabbitMQ 进行消息异步处理,使用 WebSocket 实现消息实时推送,具备用户登录、好友系统、群组管理、消息存储与离线推送等功能,支持高并发和水平扩展。 主要功能: 用户注册 / 登录、鉴权与会话管理(基于JWT) 私聊与群聊功能,支持文本、表情、图片等类型的消息 WebSocket 实时通信,心跳检测与连接断线重连机制 消息持久化与离线消息存储,历史消息查询接口 群组创建、成员管理、群公告、群消息同步等功能 使用 RabbitMQ + Topic Exchange 进行消息路由与分发,解耦发送与处理逻辑 Redis 实现用户在线状态记录与消息缓存 接入 Prometheus + Grafana 实现服务监控,支持多实例部署与负载均衡 ## 架构设计 已生成图片 # 功能 ## 私聊 创建一个用户单独的队列,每个请求都发送到这个队列 ## 群聊 使用广播交换机**Fanout Exchange** / **Direct/Topic Exchange** - 写扩散 - 读扩散 # 群聊与私聊实现方案 ------ ## 1. 系统架构概述 - **前端**:通过 WebSocket 建立与服务器的长连接,实时发送和接收消息。 - **后端**: - 使用 Go 语言和 Gin 框架处理 HTTP/WebSocket 连接。 - 使用 RabbitMQ 作为消息中间件,负责消息的发布与订阅、路由转发。 - **消息队列**: - 交换机采用 **Topic Exchange**,根据 routing key 动态路由消息。 - 每个用户拥有专属队列,负责接收发给自己的私聊消息及其所加入群聊的群消息。 ------ ## 2. 消息模型 ``` json复制编辑{ "message": "消息内容", "to": "接收者ID或群ID", "type": "消息类型,0-私聊,1-群聊", "from": "发送者ID", "group_id": 1, "createTime": "2025-06-18T13:24:00Z" } ``` - `type=0` 表示私聊,消息通过私聊 routing key 路由(格式如 `private.id.{userId}`) - `type=1` 表示群聊,消息通过群聊 routing key 路由(格式如 `group.id.{groupId}`) ------ ## 3. RabbitMQ 设计 ### 3.1 交换机 - 统一使用一个 Topic 交换机,比如 `message.topic` - 交换机持久化(`durable=true`),确保服务器重启消息不过期 ### 3.2 队列 - 每个用户对应一个独立队列(如 `queue.user.{userId}`) - 队列绑定多个 routing key,接收私聊和加入群的消息 ### 3.3 Routing Key 设计 | 用途 | 格式 | 说明 | | ---- | --------------------- | ----------------------------- | | 私聊 | `private.id.{userId}` | 只发给指定用户 | | 群聊 | `group.id.{groupId}` | 群内所有成员对应队列绑定此key | ------ ## 4. 消息路由与订阅流程 ### 4.1 用户私聊订阅 - 用户队列绑定对应私聊 routing key 例如用户 100 的队列绑定 `private.id.100` ### 4.2 用户群聊订阅 - 用户加入群聊时,队列动态绑定群聊 routing key 例如群 10,用户 100 加入,则绑定 `group.id.10` - 用户退出群聊时,解绑对应 routing key ------ ## 5. 动态绑定和解绑 Routing Key 示例 ``` go复制编辑// 绑定 routing key(加入群聊) func BindRoutingKey(ch *amqp.Channel, queueName, exchangeName, routingKey string) error { return ch.QueueBind(queueName, routingKey, exchangeName, false, nil) } // 解绑 routing key(退出群聊) func UnbindRoutingKey(ch *amqp.Channel, queueName, exchangeName, routingKey string) error { return ch.QueueUnbind(queueName, routingKey, exchangeName, nil) } ``` ------ ## 6. WebSocket 与消息消费 ``` go复制编辑r.GET("/ws", func(c *gin.Context) { // WebSocket 升级 upgrader := websocket.Upgrader{CheckOrigin: func(r *http.Request) bool { return true }} conn, err := upgrader.Upgrade(c.Writer, c.Request, nil) if err != nil { panic(err) } defer conn.Close() // 假设从请求参数或认证中获取用户ID userId := c.Query("user_id") queueName := "queue.user." + userId exchangeName := "message.topic" ch, _ := rabbitMQConn.Channel() defer ch.Close() // 订阅用户专属队列,消费消息推送到 WebSocket go func() { msgs, _ := ch.Consume(queueName, "", true, false, false, false, nil) for d := range msgs { err := conn.WriteMessage(websocket.TextMessage, d.Body) if err != nil { break } } }() // 读取客户端消息并发布到交换机 for { _, msg, err := conn.ReadMessage() if err != nil { break } // 解析消息,确定 routing key var payload MessagePayload json.Unmarshal(msg, &payload) var routingKey string if payload.Type == "0" { // 私聊 routingKey = "private.id." + payload.To } else if payload.Type == "1" { // 群聊 routingKey = "group.id." + strconv.Itoa(payload.GroupId) } ch.Publish(exchangeName, routingKey, false, false, amqp.Publishing{ ContentType: "application/json", Body: msg, }) } }) ``` ------ ## 7. 总结 | 功能 | 说明 | | ------------- | ------------------------------------------------------------ | | 私聊 | 交换机通过 routing key `private.id.{userId}` 路由私聊消息给指定用户队列 | | 群聊 | 用户队列动态绑定对应群聊 routing key,交换机广播群消息到所有成员队列 | | 动态绑定解绑 | 用户加入或退出群聊时调用 RabbitMQ API 动态修改 routing key 绑定关系 | | WebSocket推送 | 消费者监听用户队列,实时推送消息到客户端 WebSocket | | 消息发送 | 客户端发消息到后端,由后端发布到交换机指定 routing key | ------ 如果需要,我还可以帮你写一份更详细的接口设计说明或配套代码示例。你看怎么样? 工具 ChatGPT 也可能会犯错。请核查重要信息。