Jack Jiang

我的最新工程MobileIMSDK:http://git.oschina.net/jackjiang/MobileIMSDK
posts - 522, comments - 13, trackbacks - 0, articles - 1

2025年10月16日

本文由自字节跳动技术肖新蔚、赵彦奇分享,有修订和重新排版。

1、引言

本文要分享的是字节跳动团队针对火山HTTPDNS Cache2.0通过自研网段库与动态划分算法,将缓存粒度从“城市-运营商”细化为“网段”,解决了传统方案的城市级调度污染问题。配合缓存分级、预取等优化,在提升调度精准度的同时保证了高命中率,最终实现了服务端调度准确性提升和客户端性能优化。

cover-opti

技术交流:

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK备用地址点此

(本文已同步发布于:http://www.52im.net/thread-4876-1-1.html

2、系列文章

移动端弱网优化专题(一):通俗易懂,理解移动网络的“弱”和“慢”

移动端弱网优化专题(二):史上最全移动弱网络优化方法总结

移动端弱网优化专题(三):现代移动端网络短连接的优化手段总结

移动端弱网优化专题(四):百度APP网络深度优化实践(DNS优化篇)

移动端弱网优化专题(五):百度APP网络深度优化实践(网络连接优化篇)

移动端弱网优化专题(六):百度APP网络深度优化实践(移动弱网优化篇)

移动端弱网优化专题(七):爱奇艺APP网络优化实践(网络请求成功率优化篇)

移动端弱网优化专题(八):美团点评的网络优化实践(大幅提升连接成功率、速度等)

移动端弱网优化专题(九):淘宝移动端统一网络库的架构演进和弱网优化实践

移动端弱网优化专题(十):爱奇艺APP跨国弱网通信的优化实践

移动端弱网优化专题(十一):美图APP的移动端DNS优化实践

移动端弱网优化专题(十二):得物自研移动端弱网诊断工具的技术实践

移动端弱网优化专题(十三):得物移动端常见白屏问题优化(网络优化篇)

移动端弱网优化专题(十四):携程APP移动网络优化实践(弱网识别篇)

移动端弱网优化专题(十五):字节跳动移动端网络HttpDNS优化实践》(☜ 本文

3、技术背景

在字节跳动的业务生态中,HTTPDNS 承担着为抖音、今日头条、西瓜视频等核心应用提供域名解析服务的重任。但目前我们所采用的业界主流缓存机制(火山Cache1.0),却存在着调度不准的问题。

这些问题主要是:

  • 1)业界主流缓存机制的问题;
  • 2)缓存粒度:城市-运营商;
  • 3)致命缺陷:当自身IP库与权威DNS服务器不同,易发生调度不准,可能影响用户体验。

4、主流HttpDNS调度修正机制的局限性

针对 HTTPDNS 调度不准风险,业界主流处置流程采用 “发现-定位-修复” 三步闭环机制.

具体如下:

  • 1)发现:通过监控告警、业务异常反馈等方式,识别存在调度偏差的解析场景;
  • 2)定位:结合访问日志、链路追踪数据等,定位调度不准的具体域名、源IP段和目标 IP 段;
  • 3)修复:通过技术手段修正解析结果。

针对上述第 3)点,核心修复方式包含以下两类(均存在显著局限性):

  • 1)地址库升级:基于外部供应商数据聚合构建的 IP 地址库,即使实时更新,仍难与外部 CDN 厂商的映射保持一致;
  • 2)临时劫持:手动配置解析劫持规则修正解析结果,不仅操作流程繁琐、耗时长,且需人工维护大量静态配置;若规则未得到及时维护,易引发解析结果异常。 
1

5、主流厂商的HttpDNS缓存粒度技术方案

缓存粒度设计直接影响 DNS 解析精准度,主流厂商的方案存在明显差异:

2

6、HttpDNS的缓存键精细化重构

我们综合考量调度精准度、工程复杂度以及成本,决定将缓存粒度由“城市+运营商”细化为“网段”。

6.1 传统方案(国内某厂商/火山Cache1.0)

3

  • 1)缓存粒度:城市+运营商;
  • 2)污染范围:整个城市运营商;
  • 3)调度准确性:低。

6.2 Cache2.0方案

4
  • 1)缓存粒度:网段;
  • 2)污染范围:单个网段;
  • 3)调度准确性:高。

6.3 网段自适应划分算法

背景:外部 CDN 厂商的调度结果会随网络拓扑和调度策略持续变化,而静态网段库划分方式固定,难以实时跟踪调度结果变化。

为解决这一问题,网段库动态划分算法通过“数据输入—一致性校验—网段调整—结果输出”的闭环流程,实现了网段库的自适应动态划分。

具体流程如下。

1)数据输入:

* 收集客户端IP—CDN IP映射数据:

  • a)数据来源:主动拨测结果;HTTPDNS 递归节点日志;
  • b)数据范围:主流CDN厂商的解析结果。

* 网段归属判断:

  • a)若相邻客户端IP的CDN IP 归属同一运营商,则该组CIP可合并为连续网段;
  • b)将合并后的连续网段输出,作为探测网段数据集。

2)一致性校验:

  • a)将探测网段数据集与存量CIDRDB网段库进行逐网段对比,检查 “映射一致性”;
  • b)若存在映射不一致,则触发网段调整流程。

3)网段调整:

  • a)合并:探测数据集的网段比现有库粗,合并为大网段;
  • b)拆分:探测数据集的网段比现有库细,拆分为小网段。

4)结果输出:

  • a)生成优化后的新CIDRDB网段库;
  • b)替换存量网段库,实现动态更新。

5)持续迭代:

  • a)重复上述流程,实现网段库的自适应动态划分。
5

7、HttpDNS的缓存策略优化

为解决缓存粒度细化可能导致的命中率下降问题,Cache2.0 引入了四重优化策略,最终实现了如下收益:

缓存命中率提高了15%,缓存量、CPU 使用和出网流量降低了约70%。

1)两级一致性哈希分流:

火山 HTTPDNS 的流量转发以一致性哈希思想为核心,将用户请求链路(用户→LB→缓存层→递归层)拆分为两级哈希调度:

  • a)一级调度(LB→缓存层):以“源 IP + 域名”为哈希键。使用LB的一致性哈希策略,将同一用户对同一域名的请求统一路由至固定的 HTTPDNS 节点,避免传统轮询导致的请求分散;
  • b)二级调度(缓存层→递归层):以“域名 + 网段” 为哈希键。以 “域名 + 客户端网段” 作为哈希键,与缓存粒度完全对齐,确保某一“域名 + 网段”对应的查询请求均定向到唯一的递归层节点。

两级哈希协同调度,解决了缓存的碎片化问题,同时单一节点故障影响范围极小。

6

 


 

2)缓存分级管理:

在 HTTPDNS 场景中,不同域名对解析精度的需求不同。高优先级域名(如API 调用、直播 / 点播流媒体分发)对解析精准性要求高,跨网可能导致访问延迟增加;而低精度需求域名(如302域名)采用过细缓存会浪费存储资源,频繁回源也会增加权威 DNS 压力。

为实现缓存资源的精细化分配,火山 HTTPDNS 将缓存体系划分为“网段缓存、城市 - 运营商缓存、全局缓存” 三级,各级缓存适配不同应用场景。

具体是:

1)网段缓存:作为最高精度层级,聚焦高优先级业务场景 :一方面适配高优域名(如抖音 API 调用、图片分发、点播 / 直播流媒体传输等对精准性敏感的域名),另一方面服务重点集群(如 ToB 企业 HTTPDNS 服务、ToB 专属公共 DNS 服务),通过网段级细粒度缓存确保解析结果与用户实际网络链路高度匹配,降低访问延迟;

2)城市 - 运营商缓存:定位中等精度层级,适配普通域名场景:针对调度精准度要求较低的域名,以 “城市 + 运营商” 为缓存单元,平衡缓存命中率与存储开销;

3)全局缓存:作为基础精度层级,专门适配非智能解析域名:针对不支持 CDN 动态调度、解析结果无地域 / 运营商差异的域名(如静态官网、通用工具类服务域名),采用全局统一缓存策略,所有用户查询共享同一缓存结果,最大化提升缓存命中率,降低回源请求压力。

7

3)缓存更新分级策略:

在 HTTPDNS 系统中,统一的主动刷新策略虽然能保证缓存命中率,但存在明显问题:对不需要精细调度的域名浪费了存储资源,增加了下游压力。

基于以上问题,火山 HTTPDNS引入 “主动刷新 + 被动刷新”分级策略,以域名优先级和业务需求为依据,将缓存更新机制分为两类。

具体是:

  • a)后台线程主动刷新机制:针对高优域名(白名单),保留后台线程主动刷新,确保缓存持续有效、用户请求直接命中最新数据;
  • b)用户请求被动刷新机制:针对普通域名或非智能解析域名,由请求触发缓存更新,按需刷新,无需常驻后台刷新线程,降低资源消耗。

通过这种分级更新策略,高优先级域名仍能保证低延迟和高命中率,同时普通域名的刷新开销显著降低。

4)缓存预取机制:

依托 “缓存空间局部性原理”,火山 HTTPDNS 设计了缓存预取机制。当某条缓存请求(如 A 网段域名解析)触发更新时,系统不仅刷新目标网段缓存,还会同步更新与其具有 “亲缘关系” 的网段缓存(“亲缘关系”指地理相邻、同运营商节点覆盖的网段)。这种 “单次请求触发批量预取” 的设计能够提前将关联网段缓存置于准备状态,提升后续请求的命中率。

以抖音直播域名的实际访问场景为例,预取机制的运作过程如下:

  • a)本网段更新:当用户 A(IP 归属北京联通 10.0.1.0/24 网段)发起直播域名解析请求时,系统首先刷新其所属的 10.0.1.0/24 网段缓存;
  • b)预取更新:系统同时刷新与 10.0.1.0/24 网段具有亲缘关系的网段缓存,例如北京联通下的相邻网段(10.0.2.0/24、10.0.3.0/24),确保这些网段缓存也处于准备状态。

随后,当用户 B(10.0.2.0/24)或用户 C(10.0.10.0/24)发起相同直播域名的解析请求时,由于对应网段缓存已提前预取,无需等待回源即可直接命中缓存,显著降低访问延迟。

8、HttpDNS优化后的实际效果

8

服务端调度精准度提高:借助网段级缓存,用户获取的 IP 地址更加精准。按服务端日志数据口径,调度不准比例从万分之六下降至万分之二,降幅 60%,有效缓解了传统粗粒度缓存导致的“城市级缓存污染”问题。

客户端性能优化:

  • 1)成功率:核心 feed 接口,在弱网+非连接复用场景下提升 1.15%;
  • 2)耗时:非连接复用场景耗时减少14ms。
9

用户体验提升:

  • 1)性能指标:首刷及启动耗时下降;
  • 2)用户指标:用户行为指标(send 与 click)正向,用户活跃度提升。

本方案通过服务端精准调度 → 客户端性能优化 → 用户体验提升,实现了全链路效能提升。

9、持续演进方向——共享缓存

目前,各机房的负载均衡策略与缓存策略未能完全对齐(部分采用随机转发,部分虽然使用一致性哈希但粒度不一致),导致同一数据在多个实例中被重复缓存,资源利用率偏低,缓存命中率也有待提升。

未来,我们计划构建一个分层共享的高可用缓存体系:

1)在同一机房内,实例通过一致性哈希协同分工,每台实例既是分片缓存,也能代理转发请求,从而减少重复存储并提升命中率;

2)在跨机房层面,按区域部署二级缓存节点,作为容量更大、延迟更低的共享中心,承接一级未命中的请求,降低跨区域访问和上游压力。与此同时,引入热点数据副本、请求合并和故障转移等机制,保证高并发和异常情况下的稳定性与可用性。

通过这一演进,整体架构将逐步升级为层次化、分布式且具备高可用能力的缓存网络,为业务的持续扩展提供坚实支撑。

10、参考资料

[1] TCP/IP详解 卷1:协议 - 第14章 DNS:域名系统

[2] 网络编程懒人入门(七):深入浅出,全面理解HTTP协议

[3] 网络编程懒人入门(十二):快速读懂Http/3协议,一篇就够!

[4] 从HTTP/0.9到HTTP/2:一文读懂HTTP协议的历史演变和设计思路

[5] 脑残式网络编程入门(三):HTTP协议必知必会的一些知识

[6] 全面了解移动端DNS域名劫持等杂症:原理、根源、HttpDNS解决方案等

[7] 通俗易懂,理解移动网络的“弱”和“慢”

[8] 现代移动端网络短连接的优化手段总结

[9] 百度APP网络深度优化实践(DNS优化篇)

[10] 爱奇艺APP网络优化实践(网络请求成功率优化篇)

[11] 美团点评的网络优化实践(大幅提升连接成功率、速度等)

[12] 淘宝移动端统一网络库的架构演进和弱网优化实践

[13] 爱奇艺APP跨国弱网通信的优化实践

[14] 得物自研移动端弱网诊断工具的技术实践

[15] 携程APP移动网络优化实践(弱网识别篇)

(本文同步发布于:http://www.52im.net/thread-4876-1-1.html

posted @ 2025-11-25 10:45 Jack Jiang 阅读(16) | 评论 (0)编辑 收藏

本文来自转转技术李帅的原创分享,已进行修订和排版优化。

1、引言

在当今互联网时代,高效的用户服务是提升用户体验的关键。转转自研的客服IM聊天系统作为用户与客服沟通的桥梁,承担着传递信息、解决问题的关键角色。然而,消息数据的流转并非一帆风顺,本文将深入探讨IM系统在消息传递过程中遇到的问题和挑战,以及相应的技术解决方案。

如图是IM系统中一条消息的流转链路:

 1

相较于普通web系统,IM系统的消息数据流转链路更长、更复杂。从客户端到服务端,再从服务端到另一个客户端,任何一个环节的故障都可能导致消息延迟、丢失、乱序或重复,从而影响用户体验。

网络波动和客户端设备性能的不稳定性是影响IM系统性能的主要因素,这些因素可能导致消息的实时性、可靠性和完整性受到威胁。

技术交流:

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK备用地址点此

(本文已同步发布于:http://www.52im.net/thread-4874-1-1.html

2、关于作者

李帅:转转履约中台研发工程师,主要负责客服工单、IM等系统研发。

3、如何保证聊天消息的实时性

首当其冲的就是消息延迟问题:当一条消息发出后,我们的系统需要确保这条消息最快被接收人感知并获取到,并且保证资源消耗较少。

这里关键的点是:

  • 1)最快触达;
  • 2)耗费资源少。

方案1:长短轮询

在PC web早期,大部分应用都是采用“一问一答”的请求响应模式来获取数据,IM系统采用客户端轮询的方式,定期、高频轮询获取服务端的新消息。这种方式开发成本较低、容易实现,但是高频轮询很多请求是无用请求,客户端浪费流量和电量,服务端资源压力很大。

后来基于短轮询进化出长轮询模式,相较于前者,后者在请求时获取到新数据时不会立即返回,而是在服务端保持连接等待一段时间,如果等待期间有新消息就立即返回响应,长轮询仅仅解决了客户端的无用消耗,但是服务端资源高负载情况依然未能解决。

方案2:WebSocket

随着HTML5的出现,全双工的WebSocket成为解决这一问题的关键。基于WebSocket实现的IM服务,客户端和服务端只需要完成一次握手,就可以创建持久的长连接,并进行随时的双向数据传输。

2
经过比较转转客服IM系统采用了WebSocket协议,具体使用方式见《转转客服IM系统的WebSocket集群架构设计和部署方案》。当服务端接收到新消息时,可以通过建立的WebSocket连接,直接进行推送,保证了消息到达的实时性。

关于传统Web和现代Web的实时通信技术,可详读以下几篇:

  1. Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE
  2. 详解Web端通信方式的演进:从Ajax、JSONP 到 SSE、Websocket
  3. 网页端IM通信技术快速入门:短轮询、长轮询、SSE、WebSocket

4、什么是聊天消息的可靠性

如图是一条消息发送的核心步骤,整个过程中可以分为两个部分,消息由客户端发送到服务端(第1、2步),服务端将消息推送至另一个客户端(第3步),发送过程中任何一步出现问题都会导致消息发送失败。

3

PS:限于篇幅原因,本文不想深入探讨,有兴趣可详读《零基础IM开发入门(三):什么是IM系统的可靠性?》。

5、如何保证聊天消息触必达?

我们参考使用了TCP/IP协议中的ACK机制来实现防丢逻辑(《TCP/IP详解 - 第17章·TCP:传输控制协议》)。ACK机制是TCP/IP协议三次握手重要的一环(请详读《脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手》),用于确认对方发送信息无误。

ACK响应机制如下:

  • 1)发送者发送消息时会携带一个消息标识符(此处使用发送方id和消息发送时间戳)、并在本地维护一个“等待ACK消息列表”;
  • 2)接收者收到消息后对消息进行存储得到消息id;
  • 3)随后再将该标识回传给发送方(ACK消息);
  • 4)发送方收到ACK消息后将消息从“等待ACK消息列表”删除;
  • 5)当发送方没有在约定时间内收到ACK消息时,就需要执行失败消息处理逻辑:自动重发、客户端标记发送失败等。

服务端实现与客户端稍有不同,服务端需要要维护全量用户的消息,使用定时任务检查等待ACK消息列表效率比较低,此处通过mq的延迟消息来实现:

当消息发出时同时发送一个延迟mq,延迟消息被消费时对应的消息仍在等待ACK列表中,则表示消息未能在规定时间内被确认,需要进行重试发送。

如图为完整的ACK实现机制:

4

另外客户端也会在页面刷新、WebSocket重连时触发http接口重新拉取当前会话的所有消息进行渲染,保证消息不丢失。

PS:相关资料可进一步阅读:

  1. IM消息送达保证机制实现(一):保证在线实时消息的可靠投递
  2. 阿里IM技术分享(四):闲鱼亿级IM消息系统的可靠投递优化实践
  3. 融云技术分享:全面揭秘亿级IM消息的可靠投递机制
  4. 一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等

6、如何对聊天消息去重?

消息重推解决了消息丢失的问题,但是因为ACK消息本身就可能会丢失从而导致消息重复,因此我们需要保证推送消息和重推消息有相同且唯一的消息id,接收方可以根据该消息id进行数据去重。

具体是:

  • 1)发送方:客户端使用发送人id和消息发送时间戳作为唯一的ACK标识,传递给服务端;
  • 2)服务端:使用雪花算法接收到的消息生成消息id,将ACK标识与消息id建立映射关系;服务端再将消息id推送至发送方和接收方。

一个完整的消息发送流程如图所示:

5

7、心跳保活机制

IM系统中接收和发送消息都是使用长连接实现,但是如果连接断开,那发送和接收数据就会出现问题。在客服业务中,人工客服席位有限,系统需要可靠的机制保证人工客服资源有效利用。

为此我们在应用层设计心跳消息,使用该机制更新用户当前状态、保证会话有序退出。

心跳机制设计如下。

客户端:设置定时器,用户建立连接后,定时发送(30s)心跳消息给服务端。

服务端:

  • 1)接收心跳消息,更新心跳时间;
  • 2)设置定时任务,定时扫描在线用户上次心跳时间,执行以下逻辑;
  • 3)上次心跳时间超出30s,将其标记为离线状态,关闭连接,等待用户重连;
  • 4)上次心跳时间超出2分钟则认为用户已经彻底离开,执行会话关闭逻辑释放人工客服资源。

应用层心跳消息仅用于保活和状态更新,因此数据结构设计十分精简,不携带额外信息。

关于心跳保活这方面的资料,可以进一步阅读:

  1. 为何基于TCP协议的移动端IM仍然需要心跳保活机制?
  2. 一文读懂即时通讯应用中的网络心跳包机制:作用、原理、实现思路等
  3. 微信团队原创分享:Android版微信后台保活实战分享(网络保活篇)
  4. 融云技术分享:融云安卓端IM产品的网络链路保活技术实践
  5. 跟着源码学IM(五):正确理解IM长连接、心跳及重连机制,并动手实现
  6. 阿里IM技术分享(五):闲鱼亿级IM消息系统的及时性优化实践
  7. 万字长文:手把手教你实现一套高效的IM长连接自适应心跳保活机制

8、消息协议的设计

在IM系统中消息格式的设计也十分重要,良好的数据格式可以准确传递消息内容并具有极高的可读性。

我们根据消息类型和发送流向将消息数据格式大致分为如下几部分:

  • 1)消息类型:用于描述消息的用途、流向,如心跳消息、用户/客服消息、系统消息等;
  • 2)客服id:接收或者发送消息的客服标识;
  • 3)用户id:接收或者发送消息的用户标识;
  • 4)消息内容:实际的消息,与消息类型相关;
  • 5)消息格式:用于描述用户/客服消息格式,如文本、图片、视频、订单卡片、优惠券等;
  • 6)消息文本:消息的展示内容。
6

PS:IM协议设计相关资料可进一步阅读:

  1. 简述移动端IM开发的那些坑:架构设计、通信协议和客户端
  2. 理论联系实际:一套典型的IM通信协议设计详解
  3. APP与后台通信数据格式的演进:从文本协议到二进制协议
  4. IM通讯协议专题学习(一):Protobuf从入门到精通,一篇就够!

9、本文小结

转转客服IM系统通过引入WebSocket协议、ACK机制、消息重推和数据去重等策略,有效应保障了消息传递过程中的实时性、可靠性和完整性。这些技术的应用,不仅提升了用户与客服之间的沟通效率,也为转转平台提供了更加稳定、高效的服务支持。

在未来的发展中,我们将继续优化和完善,以应对不断变化的需求和用户期望,为用户提供更加优质的服务体验。

10、参考资料

[0] TCP/IP详解 - 第17章·TCP:传输控制协议

[1] Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE

[2] 详解Web端通信方式的演进:从Ajax、JSONP 到 SSE、Websocket

[3] 网页端IM通信技术快速入门:短轮询、长轮询、SSE、WebSocket

[4] Web端即时通讯实践干货:如何让你的WebSocket断网重连更快速?

[5] 简述移动端IM开发的那些坑:架构设计、通信协议和客户端

[6] IM消息送达保证机制实现(一):保证在线实时消息的可靠投递

[7] 阿里IM技术分享(四):闲鱼亿级IM消息系统的可靠投递优化实践

[8] 阿里IM技术分享(五):闲鱼亿级IM消息系统的及时性优化实践

[9] 融云技术分享:全面揭秘亿级IM消息的可靠投递机制

[10] 一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等

[11] 理解IM消息“可靠性”和“一致性”问题,以及解决方案探讨

[12] 微信团队分享:来看看微信十年前的IM消息收发架构,你做到了吗

[13] 阿里IM技术分享(七):闲鱼IM的在线、离线聊天数据同步机制优化实践

[14] IM群聊消息如此复杂,如何保证不丢不重?

[15] 开发IM是自己设计协议用字节流好还是字符流好?

[16] 零基础IM开发入门(一):什么是IM系统?

[17] 零基础IM开发入门(二):什么是IM系统的实时性?

[18] 零基础IM开发入门(三):什么是IM系统的可靠性?

[19] 零基础IM开发入门(四):什么是IM系统的消息时序一致性?

[20] 脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手

本文已同步发布于:http://www.52im.net/thread-4874-1-1.html

posted @ 2025-11-11 19:49 Jack Jiang 阅读(39) | 评论 (0)编辑 收藏

1、前言

经常发现有开发者将密钥硬编码在Java代码、文件中,这样做会引起很大风险。

信息安全的基础在于密码学,而常用的密码学算法都是公开的,加密内容的保密依靠的是密钥的保密,密钥如果泄露,对于对称密码算法,根据用到的密钥算法和加密后的密文,很容易得到加密前的明文;对于非对称密码算法或者签名算法,根据密钥和要加密的明文,很容易获得计算出签名值,从而伪造签名。

密钥硬编码在代码中,而根据密钥的用途不同,这导致了不同的安全风险,有的导致加密数据被破解,数据不再保密,有的导致和服务器通信的加签被破解,引发各种血案,本文主要借用乌云上已公布的几个APP漏洞来讲讲这其中的潜在风险和危害。

技术交流:

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

(本文已同步发布于:http://www.52im.net/thread-312-1-1.html)

2、风险案例(一):某互联网金融APP加密算法被破解导致敏感信息泄露

某P2P应用客户端,用来加密数据的DES算法的密钥硬编码在Java代码中,而DES算法是对称密码算法,既加密密钥和解密密钥相同。

反编译APP,发现DES算法:

1

发现DES算法的密钥,硬编码为“yrdAppKe”,用来加密手势密码:

2

将手势密码用DES加密后存放在本地LocusPassWordView.xml文件中:

3

知道了密文和加密算法以及密钥,通过解密操作,可以从文件中恢复出原始的手势密码。或者使用新的生成新的手势密码,而与服务器通信时接口中的Jason字段也用了DES算法和密钥硬编码为“yRdappKY”:

4

5

和服务器通信采用http传输,没有使用https来加密通信,如果采用中间人攻击或者路由器镜像,获得流量数据,可以破解出用户的通信内容。

3、风险案例(二):某租车APP加密算法被破解导致一些列风险

某租车APP与服务器通信的接口采用http传输数据,并且有对传输的部分参数进行了加密,加密算法采用AES,但是密钥硬编码在java代码中为“shenzhoucar123123”,可被逆向分析出来,导致伪造请求,结合服务器端的漏洞,引起越权访问的风险,如越权查看其它用户的订单等。

和服务器通信时的数据为:

6

q字段是加密后的内容。逆向APP,从登录Activity入手:

7

分析登录流程:

v1是用户名,v2是密码,v3是PushId,在用户名和密码不为空并且长度不小于11情况下,执行LoginOperate相关操作,追踪LoginOperate的实现,发现继承自BaseOperate,继续追踪BaseOperate的实现。

8

在BaseOperate的initUrl()方法中,找到了APP是怎么生成请求数据的:

9

继续追踪上图中的initJsonUrl()方法,发现其调用了AES加密:

10

继续追踪aes.onEncrypt()函数:

11

在onEncrypt()函数中调用了encrypt()函数用来加密数据,追踪encrypt()函数的实现:

发现其使用AES算法,并且密钥硬编码在java代码中为“shenzhoucar123123”。

12

构造{“id”:”11468061”}的请求:

到现在请求中的数据加密如何实现的就清晰了,另外由于服务器权限控制不严,就可以构造订单id的请求,达到越权访问到其他用户的订单。

13

其中uid设置为你自己的uid即可,可以成功看到其他人的订单:

14

攻击者完全可以做到使用其他脚本重新实现相同的加密功能并拼接出各个接口请求,批量的刷取订单信息和用户其他信息。

4、风险案例(三):某酒店APP加签算法被破解导致一系列风险

某酒店APP和服务器通信时接口采用http通信,数据进行了加密,并且对传输参数进行签名,在服务器端校验签名,以检查传输的数据是否被篡改,但是加签算法和密钥被逆向分析,可导致加签机制失效,攻击者可任意伪造请求包,若结合服务器端的权限控制有漏洞,则可引发越权风险等。

APP和服务器通信的原始包如下图,可以看到有加签字段sign:

15

逆向APP定位到加密算法的逻辑代码,com.htinns.biz.HttpUtils.class,其实现逻辑为:

16

原始数据是unSignData,使用RC4算法加密,密钥为KEY变量所代表的值,加密后的数据为signData,传输的数据时的data字段为signData。 加签字段signd的生成方法是用unsignData拼接时间戳time和resultkey,然后做md5,再进行base64编码。时间戳保证了每次请求包都不一样。 sendSign()算法是用c或c++写的,放入了so库,其他重要算法都是用java写的。

可以使用IDA逆向分析so库,找到sendSign()方法:

17

而乌云漏洞提交者采用的是分析sign和getSign(sign)的数据,做一个算法破解字典。其实还有种方法直接调用此so库,来生成字典。签名破解以后,就可以构造发送给服务器的数据包进行其他方面的安全测试,比如越权、重置密码等。

5、总结及建议

通过以上案例,并总结下自己平时发现密钥硬编码的主要形式有:

  • 1)密钥直接明文存在sharedprefs文件中,这是最不安全的。
  • 2)密钥直接硬编码在Java代码中,这很不安全,dex文件很容易被逆向成java代码。
  • 3)将密钥分成不同的几段,有的存储在文件中、有的存储在代码中,最后将他们拼接起来,可以将整个操作写的很复杂,这因为还是在java层,逆向者只要花点时间,也很容易被逆向。
  • 4)用ndk开发,将密钥放在so文件,加密解密操作都在so文件里,这从一定程度上提高了的安全性,挡住了一些逆向者,但是有经验的逆向者还是会使用IDA破解的。
  • 5)在so文件中不存储密钥,so文件中对密钥进行加解密操作,将密钥加密后的密钥命名为其他普通文件,存放在assets目录下或者其他目录下,接着在so文件里面添加无关代码(花指令),虽然可以增加静态分析难度,但是可以使用动态调式的方法,追踪加密解密函数,也可以查找到密钥内容。

保证密钥的安全确是件难事,涉及到密钥分发,存储,失效回收,APP防反编译和防调试,还有风险评估。可以说在设备上安全存储密钥这个基本无解,只能选择增大攻击者的逆向成本,让攻击者知难而退。而要是普通开发者的话,做妥善保护密钥这些事情这需要耗费很大的心血。

产品设计者或者开发者要明白自己的密钥是做什么用的,重要程度怎么样,密钥被逆向出来会造成什么风险,通过评估APP应用的重要程度来选择相应的技术方案。

6、参考资料

[1] https://www.zhihu.com/question/35136485/answer/84491440

[2] 传输层安全协议SSL/TLS的Java平台实现简介和Demo演示

[3] 理论联系实际:一套典型的IM通信协议设计详解(含安全层设计)

[4] 微信新一代通信安全解决方案:基于TLS1.3的MMTLS详解

[5] 来自阿里OpenIM:打造安全可靠即时通讯服务的技术实践分享

[6] 简述实时音视频聊天中端到端加密(E2EE)的工作原理

[7] 移动端安全通信的利器——端到端加密(E2EE)技术详解

[8] Web端即时通讯安全:跨站点WebSocket劫持漏洞详解(含示例代码)

[9] 通俗易懂:一篇掌握即时通讯的消息传输安全原理

[10] IM开发基础知识补课(四):正确理解HTTP短连接中的Cookie、Session和Token

[11] 快速读懂量子通信、量子加密技术

[12] 一分钟理解 HTTPS 到底解决了什么问题

[13] 一篇读懂HTTPS:加密原理、安全逻辑、数字证书等

[14] 基于Netty的IM聊天加密技术学习:一文理清常见的加密概念、术语等

[15] 手把手教你为基于Netty的IM生成自签名SSL/TLS证书

[16] 微信技术分享:揭秘微信后台安全特征数据仓库的架构设计

[17] 即时通讯初学者必知必会的20个网络编程和通信安全知识点

[18] 零基础IM开发入门(五):什么是IM系统的端到端加密?

7、IM安全系列文章

本文是IM通讯安全知识系列文章中的第 3 篇,总目录如下:

即时通讯安全篇(一):正确地理解和使用Android端加密算法

即时通讯安全篇(二):探讨组合加密算法在IM中的应用

即时通讯安全篇(三):常用加解密算法与通讯安全讲解

即时通讯安全篇(四):实例分析Android中密钥硬编码的风险》(☜ 本文)

即时通讯安全篇(五):对称加密技术在Android上的应用实践

即时通讯安全篇(六):非对称加密技术的原理与应用实践

即时通讯安全篇(七):用JWT技术解决IM系统Socket长连接的身份认证痛点

即时通讯安全篇(八):如果这样来理解HTTPS原理,一篇就够了

即时通讯安全篇(九):你知道,HTTPS用的是对称加密还是非对称加密?

即时通讯安全篇(十):为什么要用HTTPS?深入浅出,探密短连接的安全性

即时通讯安全篇(十一):IM聊天系统安全手段之通信连接层加密技术

即时通讯安全篇(十二):IM聊天系统安全手段之传输内容端到端加密技术

即时通讯安全篇(十三):信创必学,一文读懂什么是国密算法

即时通讯安全篇(十四):网络端口的安全防护技术实践

即时通讯安全篇(十五):详解硬编码密码的泄漏风险及其扫描原理和工具


(本文已同步发布于:http://www.52im.net/thread-312-1-1.html)

posted @ 2025-10-30 11:24 Jack Jiang 阅读(39) | 评论 (0)编辑 收藏

本文由宅小年分享,感谢原作者,下文有修订和重新排版。

1、引言     

你有没有想过,为什么 ChatGPT 能够像人类聊天一样,一个字一个字地"蹦"出来回答你的问题?为什么股票软件能够实时更新价格,而不需要你疯狂刷新页面?

答案就藏在今天我们要聊的技术里——SSE(Server-Sent Events)!

本文将带你快速认识SSE实时通信协议,包括它的技术原理、常见使用场景、与同类技术的对比以及简单的示例代码等。

cover_opti

技术交流:

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

(本文已同步发布于:http://www.52im.net/thread-4872-1-1.html)

2、AI大模型实时通信技术专题

技术专题系列文章目录如下,本文是第 4 篇:

全民AI时代,大模型客户端和服务端的实时通信到底用什么协议?

大模型时代多模型AI网关的架构设计与实现

通俗易懂:AI大模型基于SSE的实时流式响应技术原理和实践示例

ChatGPT如何实现聊天一样的实时交互?快速读懂SSE实时“推”技术 》(☜ 本文)

《AI大模型时代爆火的SSE技术到底是什么?一文读懂SSE技术的方方面面(下期发布!)》

3、什么是SSE?

我们用一个饭店的比喻来解释:

1)轮询:你点了菜之后,每隔一会儿就跑去问服务员:“我的菜好了没?”

2)SSE:你点了菜,安心坐着。饭做好了,服务员主动来告诉你:“上菜啦!”

3)WebSocket:你和服务员之间装了个对讲机,随时可以互相说话;

4)SSE(Server-Sent Events):一种基于HTTP的单向通信协议,允许服务器主动向浏览器推送数据。它就像一根从服务器连到浏览器的“数据水管”,打开后服务器可以随时通过这根管子“浇水”(推送数据)。

SSE核心技术特点:

1)单向通信:服务器 → 浏览器(像广播电台)

2)基于HTTP:无需特殊协议

3)自动重连:网络中断会自动恢复

4)轻量级:原生浏览器支持,无需额外库

5)低延迟:数据实时到达(毫秒级)。

4、SSE与其他实时通信技术的对比

我们来看一张直观的对比表:


 

场景选择指南:

1)选SSE:当只需要服务器单向推送时(如新闻推送、监控仪表盘),SSE 是最简单省事的选择。

2)选WebSocket:需要双向实时通信(如在线游戏),那就请 WebSocket 登场。

3)选轮询/长轮询:如果只是偶尔有数据变化,使用轮询也许更简单粗暴。

精妙比喻:

1)SSE 像收音机(只能接收信号)

2)WebSocket 像电话(双向通话)

3)轮询 像不断翻信箱查信

4)长轮询 像守在信箱旁等邮差

关于SSE跟其它Web端实时通信技术的详细介绍,可以深入学习以下文章:

Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE

使用WebSocket和SSE技术实现Web端消息推送

详解Web端通信方式的演进:从Ajax、JSONP 到 SSE、Websocket

使用WebSocket和SSE技术实现Web端消息推送

一文读懂前端技术演进:盘点Web前端20年的技术变迁史

网页端IM通信技术快速入门:短轮询、长轮询、SSE、WebSocket

搞懂现代Web端即时通讯技术一文就够:WebSocket、socket.io、SSE

5、SSE技术原理

我们用一个图来简单描绘 SSE 的工作过程:


 

关键要素解析

1)HTTP 请求头:客户端发送 Accept: text/event-stream 告诉服务器"我要接收事件流"

2)响应格式:服务器返回 Content-Type: text/event-stream,然后持续发送数据

3)事件格式:每个事件以 data: 内容\n\n 结束,两个换行符表示事件结束

4)自动重连:连接断开后,浏览器会自动发起新的连接请求

6、SSE的常见应用场景

SSE 已经在很多产品中落地,以下是几个典型场景.

ChatGPT 的回答显示机制:


 

ChatGPT 在回答你问题时,是一句一句“打字式”输出的,没错!就是用了 SSE 来流式传输生成的内容。

后台系统消息提醒,比如:

1)有新的订单;

2)用户提交了新评论;

3)后台工单更新了状态。

4)这些提醒都可以用 SSE 来实时推送。

实时数据面板:

1)股票价格变动

2)区块链交易动态

3)设备温湿度更新

4)只需要后端每隔几秒推送一次,前端就能不断展示最新数据。

7、示例代码(前端+后端)

前端代码(浏览器 JS):

<script>

  const eventSource = new EventSource('/sse/stream');

 

  eventSource.onmessage = function(event) {

    console.log('收到消息:', event.data);

    // 可更新到页面上

  };

 

  eventSource.onerror = function(err) {

    console.error('连接出错', err);

    // 可以展示连接断开的提示

  };

</script>

后端代码示例(Java,使用 Spring Boot 示例):

@RestController

publicclass SseController {

    privatestaticfinal Map<string, sseemitter=""> emitters = new ConcurrentHashMap<>();

 

    // 浏览器连接入口

    @GetMapping("/sse-connect")

    public SseEmitter connect(@RequestParam String userId) {

        SseEmitter emitter = new SseEmitter(30 * 60 * 1000L); // 30分钟超时

        emitters.put(userId, emitter);

 

        // 发送欢迎消息

        try {

            emitter.send(SseEmitter.event()

                    .name("welcome")

                    .data("🎉 连接成功!欢迎使用 SSE 服务"));

        } catch (IOException e) {

            System.err.println("发送欢迎消息失败: " + e.getMessage());

        }

 

        emitter.onCompletion(() -> emitters.remove(userId));

        emitter.onTimeout(() -> emitters.remove(userId));

 

        return emitter;

    }

 

    // 模拟推送服务

    @Scheduled(fixedRate = 2000)

    public void pushData() {

        emitters.forEach((userId, emitter) -> {

            try {

                String json = String.format(

                        "{\"time\": \"%s\", \"value\": %.2f}",

                        LocalTime.now(), Math.random() * 100

                );

 

                // 构建符合SSE格式的消息

                emitter.send(SseEmitter.event()

                        .id(UUID.randomUUID().toString())

                        .name("system-metrics")

                        .data(json));

            } catch (IOException e) {

                emitters.remove(userId);

            }

        });

    }

}

curl --location 'localhost:18500/sse-connect?userId=1' \

--header 'Key: Accept' \

--header 'Value: text/event-stream'


 

8、本文小结

SSE 就像一个贴心的"消息推送员",让服务器能够主动把最新消息送到你面前,而不需要你频繁地去"敲门询问"。它简单易用,特别适合那些需要服务器主动推送数据的场景。

虽然 SSE 没有 WebSocket 那么"全能"(不能双向通信),但正是这种专一性让它在特定场景下变得格外实用。就像专门的快递员虽然只负责送货,但在送货这件事上做得特别专业一样。

如果你正在开发一个需要实时推送但通信不需要太复杂的应用,SSE 是一个轻量又可靠的选择,特别适合现代网页、后台系统、数据展示等场景。

写在最后:Web 开发永远不止一种解决方案。选择最合适的技术,而不是最“酷”的技术,才是工程师的智慧体现。

9、参考资料

[1] Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE

[2] SSE技术详解:一种全新的HTML5服务器推送事件技术

[3] 使用WebSocket和SSE技术实现Web端消息推送

[4] 详解Web端通信方式的演进:从Ajax、JSONP 到 SSE、Websocket

[5] 使用WebSocket和SSE技术实现Web端消息推送

[6] 一文读懂前端技术演进:盘点Web前端20年的技术变迁史

[7] WebSocket从入门到精通,半小时就够!

[8] 网页端IM通信技术快速入门:短轮询、长轮询、SSE、WebSocket

[9] 搞懂现代Web端即时通讯技术一文就够:WebSocket、socket.io、SSE

[10] 大模型时代多模型AI网关的架构设计与实现

[11] 全民AI时代,大模型客户端和服务端的实时通信到底用什么协议?

[12] 通俗易懂:AI大模型基于SSE的实时流式响应技术原理和实践示例

[13] Web端实时通信技术SSE在携程机票业务中的实践应用

(本文已同步发布于:http://www.52im.net/thread-4872-1-1.html)

posted @ 2025-10-23 10:33 Jack Jiang 阅读(39) | 评论 (0)编辑 收藏

1、MobileIMSDK开源工程

1

MobileIMSDK 是一套专门为移动端开发的开源IM即时通讯框架,超轻量级、高度提炼,一套API优雅支持UDP 、TCP 、WebSocket 三种协议,支持iOS、Android、H5、小程序、Uniapp、标准Java平台,服务端基于Netty编写。

工程同步开源地址:

2、关于RainbowChat

RainbowChat是一套基于开源IM即时通讯聊天框架 MobileIMSDK 的产品级移动端IM系统RainbowChat源于真实运营的产品,解决了大量的屏幕适配、细节优化、机器兼容问题。RainbowChat可能是市面上提供im即时通讯聊天源码的,唯一一款同时支持TCP、UDP、WebSocket三种通信协议的IM产品。与姊妹产品RainbowTalkRainbowChat-Web 技术同源,历经考验。

APP_Store_v10.2

3、v10.2 更新内容

此版更新内容更多历史更新日志):

  • 1)[优化] 修改了首页中网络断开提示ui的显示方式;
  • 2)[优化] 修改了世界频道中“免打扰”按钮;
  • 3)[优化] 修改了首页中“一键已读按钮”;
  • 4)[优化] 将世界频道改为首页列表中显示而不是独立的浮动层;
  • 5)[优化] 解决了iOS 26下聊天界面中因topLayoutGuide.length返回值异常导致的ui问题;
  • 6)[优化] 解决了iOS 26下聊天界面下方更多面板显示时会多出一个17像素的系统自带的圆角效果;
  • 7)[优化] 优化了iOS 26下聊天界面中的消息列表顶部会多出10个像素的空白;
  • 8)[优化] 给各种按钮增加了iOS 26液态玻璃点击效果;
  • 9)[优化] 其它适配iOS 26的各种细节优化。

v10.2_vs_v10

4、iOS 26上的运行效果概览

v10.2_ios26

5、iOS 26上的真机实拍概览

5

6、部分功能运行截图预览

(☞ 更多截图点此查看 ☜)

v10.2拼合总图-pct75-size50

posted @ 2025-10-16 10:54 Jack Jiang 阅读(49) | 评论 (0)编辑 收藏

Jack Jiang的 Mail: jb2011@163.com, 联系QQ: 413980957, 微信: hellojackjiang