返回
979 字
5 分钟
0 次阅读
消息不丢,靠的是一个编号

这个 bug 是家里人帮我发现的。我妈说”你爸发的图我这边没有”, 我拿过手机一看,真的没有,刷新一下又出来了。 那次之后我才认真去处理”消息会丢”这件事。

一开始我是拿时间戳排序的#

第一版每条消息带着发送方手机上的时间,收到的时候按时间排一排, 就显示出来了。写起来特别简单,我也觉得很合理 —— 时间不就是顺序吗。

结果用起来是这样:我爸那条消息排到了下面, 因为他的手机时间比实际快了十几分钟;我妈锁屏之后再打开, 一下涌进来八条,顺序是乱的。

问题的根子在:时间戳是发送方手机给的,手机时钟不准就全乱套。 而且两台手机的时间差多少,服务器根本没办法判断谁是对的。

改成服务器发号#

后来改成了最简单的办法:每来一条消息, 服务器给它盖一个自己的、连续的编号。

1 ← 妈:回来了吗
2 ← 爸:买了菜
3 ← 我:知道了
4 ← 妈:图片.jpg

号码是服务器一个人发的,就一个来源,不存在”谁的表准”这个问题。 时间戳还留着,但只用来显示”几点几分”,不用来排序。 排序永远按编号来。

客户端只需要记一件事#

这是我做完之后觉得最舒服的一点: 手机那边只要记住一个数字 —— 我已经收到第几号了。

下次再连上来的时候,不用服务器推, 客户端直接说”我这儿到 47 号了”,服务器把 48 号往后的一起给它。 断开多久都没关系,锁屏、切出去、WiFi 断一下,回来都是这一套。

服务器那边还要能处理”客户端比我还新”的情况, 比如手机上留着一份旧的本地存档、编号比服务器上的还大。 这种情况我第一次没处理,表现是页面直接白掉,什么都不显示 —— 因为它在等一个永远不会来的号。

图片和文件不能这么补#

文字消息能补,因为文字一直存在服务器硬盘上(加密的)。 图片和文件不行 —— 它们的定位就是只在内存里待五分钟,不落硬盘。

对方当时不在线就收不到了,这一点我认了,因为这是我自己定的规则: 发的图片、语音、文件只在服务端内存里放着,谁取走或者超时就丢, 一个字节都不写盘。单个文件最大 32MB,内存总共 64MB, 满了就按最老的先丢。

但直接”什么都没有”体验很差。所以现在消息还在, 点开的时候会说一句”文件已不在”。至少知道有过这么个东西, 而不是莫名其妙一片空白。

一个我解决不了的问题,也说一下#

iPhone 把它切到后台之后,收不到消息。这是苹果的规矩: 只有它自己的推送服务能把 App 叫醒,而我家这台 Mac 不在那套体系里。 要接推送就得注册账号、消息得先过人家的服务器 —— 那跟”不上云”是冲突的,所以我没做。

实际用起来是这样:打开就实时收,锁屏期间的消息在打开那一瞬间全部补上,一条不丢。 安卓那边被杀掉之后也一样,本地通知得进程活着才能弹出来。

这两条都写在 README 的”已知限制”里,标题下面第一个就是它。 我觉得写清楚比假装没有好。

这篇文章讲的东西,可以在这里下载

全部东西都在下载区, 包括模组、地图和软件。

消息不丢,靠的是一个编号
https://liyuanjie.com/posts/fourth-post/
作者
Liyuanjie
发布于
2026-06-07
许可协议
CC BY-NC-SA 4.0
这篇被看了 0 次