SSH-Chat 消息历史原理:为什么刚连上聊天室就能看到之前的对话?
SSH-Chat 消息历史原理为什么刚连上聊天室就能看到之前的对话【免费下载链接】ssh-chatChat over SSH.项目地址: https://gitcode.com/gh_mirrors/ss/ssh-chatSSH-Chat 是一款通过 SSH 协议连接的实时聊天程序它有一个容易让人好奇的细节刚进入聊天室就能看到别人刚刚发过的消息。这篇文章从这一现象出发讲清楚 SSH-Chat 消息历史如何保存在内存里、20 条的边界从哪里来以及这套 SSH 聊天存储机制为什么这样设计。 为什么刚连上就能看到别人说过的话你还没有和任何人说过话SSH 进房间后终端里却已经躺着几行对话。这就像房间有了记忆——你看到的不是实时消息而是你进来之前别人发过的内容。SSH-Chat 为每个房间都保留最近的若干条记录新用户连接后程序会主动把这些记录推送给对方。那么问题来了记录到底保留多少条满了之后会发生什么 核心方案内存里一块固定容量的环形缓冲区用一句大白话说历史不写数据库而是放在内存中一块固定容量的环形缓冲区里。环形缓冲区可以理解成一条环形跑道——写满之后写入位置不会停下而是回头覆盖跑道最前端的旧内容。几个要点容量固定为 20 条由 chat/room.go 中的常量historyLen 20决定。每个房间创建时初始化自己的独立缓冲区房间再活跃占用的内存也不变。旧消息被自动覆盖不需要额外的清理任务。房间之间互不干扰一个房间的 20 条记录与另一个房间完全隔离。 一条消息的旅程写入、移动、覆盖、取回你发出消息后程序依次做几件事。第一步写入。房间收到消息后调用 chat/message/history.go 中的History.Add()方法存起来。这个方法先拿写锁再动手多个用户同时发消息时也不会出现有人把缓冲区写到一半的混乱局面。第二步移动。缓冲区里有一个head指针标记最新一条的位置。每存一条消息head往前挪一格挪到末尾就用取模绕回起点h.head (h.head 1) % max h.entries[h.head] entry第三步写满则覆盖。缓冲区没装满时每存一条有效条数加一。装到 20 条满员后下一次写入就直接覆盖head处的最旧一条没有显式的删除步骤覆盖本身就是清理。第四步进房取回。新用户连接并加入房间时房间调用Room.History()按时间顺序取出最近的 20 条逐条发给对方。你刚进房看到的那些旧消息就是靠这一步送到终端的。 源码佐证历史推送其实只有三行推送逻辑简单得有些意外。Room.History()只干一件事——把缓冲区里的内容取出来逐条发出func (r *Room) History(u *message.User) { for _, m : range r.history.Get(historyLen) { u.Send(m) } }Get()负责从head往前回溯、按时间顺序排好返回。整个过程没有文件读取也没有数据库查询几次数组下标计算而已所以连接时的历史展示几乎没有延迟。⚖️ 设计取舍为什么不用数据库或文件聊天室的历史为什么不直接落盘到数据库或日志文件内存可控。20 条、固定长度的数组房间再多、时间再长内存上限都清清楚楚不会随运行时间膨胀。读取极快。取历史只是数组下标运算全部发生在内存里读路径非常短。无需清理。环形结构让旧消息自然被覆盖不用设计删除策略也不用担心文件无限增长。代价是不完整超过 20 条的消息找不回来。对一个聊天工具来说这个取舍是划算的。如果确实想留一份记录可以用房间的SetLogging()方法配置一个输出流之后每条新增消息都会写进去相当于给内存里的历史留一个持久化的分身。 最后说两句SSH-Chat 消息历史的价值不在存得多而在让聊天有了连续性新来的人不会被晾在一边掉线重连的人能补上错过的内容程序本身也不额外负担什么。环形缓冲区是一个小而讲究的细节内存可控、读取即时、旧消息安静退场。下次连进聊天室你看到的那几行旧消息就是房间替你回忆的最近 20 条。【免费下载链接】ssh-chatChat over SSH.项目地址: https://gitcode.com/gh_mirrors/ss/ssh-chat创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考