0

0

Golang中介者模式在多人在线聊天室逻辑中的应用

P粉602998670

P粉602998670

发布时间:2026-02-25 11:23:03

|

463人浏览过

|

来源于php中文网

原创

聊天室用mediator而非直接广播,是为了避免强耦合、统一消息分发逻辑、解耦用户状态与路由规则;它需线程安全、连接存活检查、非阻塞写入,并严格隔离职责——不存历史、不管连接生命周期、不掺和业务规则。

golang中介者模式在多人在线聊天室逻辑中的应用

为什么聊天室不用直接广播而要用 Mediator

因为直接让每个 User 持有其他所有 User 的引用,会导致对象间强耦合:加人、踢人、私聊逻辑全得手动遍历、判空、同步状态。一旦要支持「房间隔离」「消息审计」「在线状态推送」,代码立刻散落在各处,改一处漏三处。

Mediator 把路由、过滤、分发逻辑收口到一个结构体里,User 只需调用 mediator.Broadcast()mediator.SendTo(),不关心谁在线、谁掉线、谁被禁言。

常见错误现象:panic: send on closed channel —— 很多实现把 chan []byte 直接暴露给用户,没做发送前的连接存活检查;或者用 map 存用户却忘了加锁,高并发下 concurrent map writes

  • Mediator 必须持有 *sync.RWMutex,读用户列表用 RLock(),增删用 Lock()
  • 每个 User 应该带唯一 id stringconn net.Conn,不要用指针地址当 ID
  • 广播前必须检查 conn.SetWriteDeadline() 并捕获 io.ErrClosed,主动清理失效连接

Mediator.Broadcast() 怎么避免阻塞主线程

如果所有消息都同步写进每个用户的 conn.Write(),一个慢连接(比如弱网手机)会拖垮整个广播——后续消息卡在 goroutine 里排队,新用户接入延迟飙升。

立即学习go语言免费学习笔记(深入)”;

正确做法是为每个 User 启一个独立 goroutine 做写操作,并配超时控制:

go func(u *User, msg []byte) {
    u.conn.SetWriteDeadline(time.Now().Add(5 * time.Second))
    if _, err := u.conn.Write(msg); err != nil {
        mediator.Remove(u.id) // 主动下线
    }
}(user, message)

性能影响很实际:100 人房间,单次广播开 100 个 goroutine 看似吓人,但 Go runtime 调度开销极低;相比阻塞式广播导致的连接积压和内存暴涨,这是更稳的选择。

Pliny
Pliny

创建、分享和重新组合AI应用程序

下载
  • 别用 sync.WaitGroup 等全部写完——广播本就不需要强一致性
  • 写失败后,Remove() 必须加锁,且要避免在循环中直接从正在遍历的 map 删除
  • 如果消息体很大(如含图片 base64),先做序列化压缩再投递,否则 goroutine 堆积吃光内存

私聊和系统通知怎么复用同一套 Mediator

Mediator 不该只干“群发”一件事。它的核心价值是统一消息入口,所以 SendTo()Announce()Kick() 都应走同一个分发管道,只是路由规则不同。

例如系统通知(如「xxx 加入房间」)应该广播给除 sender 外所有人;私聊则只推给目标 id;而管理员指令可能还要校验 u.Role == "admin"

  • 所有方法最终都调用内部 deliver(msg Message, targets []string),复用连接检查和写逻辑
  • Message 结构体必须含 Type string 字段(如 "chat" / "join" / "kick"),前端靠它做 UI 分支
  • 别在 SendTo() 里重复写 conn.Write —— 提取成私有 writeConn(conn net.Conn, msg []byte),避免 write deadline、error 处理逻辑散落

为什么 Mediator 不该保存消息历史

有人把 Mediator 当成消息中心,往里面塞 []Message 做缓存,结果上线三天内存涨到 2GB——这不是中介者模式的问题,是职责错位。

Mediator 只管“此刻怎么送”,不管“之前送过什么”。历史记录属于领域状态,该交给单独的 MessageStore(比如基于 LRU cache 或 Redis),并由上层业务决定是否回溯、存多久、谁有权查。

容易踩的坑:Mediator 里用 slice append 积累消息,没设上限;或用 map[string][]Message 按房间存,但忘记定时清理过期房间。

  • 如果真要临时缓存(如新用户加入时补发最后 10 条),用带容量限制的 container/list,每次 PushBack() 后检查长度,超了就 Remove(Front())
  • 缓存内容必须是深拷贝后的 []byte,不能存指向原始请求 body 的指针,否则 GC 收不走
  • 任何涉及时间窗口的逻辑(如“最近 5 分钟消息”)必须用单调时钟 time.Now().UnixMilli(),别用 time.Since() 防止 NTP 校时翻车

事情说清了就结束。真正难的不是写出 Mediator,而是守住它的边界——不碰存储、不代管连接生命周期、不掺和业务规则。越往后迭代,这点越关键。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

智谱清言 - 免费全能的AI助手
智谱清言 - 免费全能的AI助手

智谱清言 - 免费全能的AI助手

相关专题

更多
golang如何定义变量
golang如何定义变量

golang定义变量的方法:1、声明变量并赋予初始值“var age int =值”;2、声明变量但不赋初始值“var age int”;3、使用短变量声明“age :=值”等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

207

2024.02.23

golang有哪些数据转换方法
golang有哪些数据转换方法

golang数据转换方法:1、类型转换操作符;2、类型断言;3、字符串和数字之间的转换;4、JSON序列化和反序列化;5、使用标准库进行数据转换;6、使用第三方库进行数据转换;7、自定义数据转换函数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

242

2024.02.23

golang常用库有哪些
golang常用库有哪些

golang常用库有:1、标准库;2、字符串处理库;3、网络库;4、加密库;5、压缩库;6、xml和json解析库;7、日期和时间库;8、数据库操作库;9、文件操作库;10、图像处理库。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

350

2024.02.23

golang和python的区别是什么
golang和python的区别是什么

golang和python的区别是:1、golang是一种编译型语言,而python是一种解释型语言;2、golang天生支持并发编程,而python对并发与并行的支持相对较弱等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

212

2024.03.05

golang是免费的吗
golang是免费的吗

golang是免费的。golang是google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的开源编程语言,采用bsd开源协议。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

405

2024.05.21

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

365

2025.06.09

golang相关判断方法
golang相关判断方法

本专题整合了golang相关判断方法,想了解更详细的相关内容,请阅读下面的文章。

200

2025.06.10

golang数组使用方法
golang数组使用方法

本专题整合了golang数组用法,想了解更多的相关内容,请阅读专题下面的文章。

1091

2025.06.17

batoto漫画官网入口与网页版访问指南
batoto漫画官网入口与网页版访问指南

本专题系统整理batoto漫画官方网站最新可用入口,涵盖最新官网地址、网页版登录页面及防走失访问方式说明,帮助用户快速找到batoto漫画官方平台,稳定在线阅读各类漫画内容。

21

2026.02.25

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Go 教程
Go 教程

共32课时 | 5.5万人学习

Go语言实战之 GraphQL
Go语言实战之 GraphQL

共10课时 | 0.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号