本文属于进阶篇,并不是太适合新人阅读,但纯粹的学习还是可以的,因为后续会实现很多个ddp的版本用于web端、nodejs端、安卓端和ios端,提前预习和复习下。ddp协议是一个C/S架构的协议,但是客户端也同时可以是服务端。
什么是DDP?
DDP (Distributed Data Protocol) 是Meteor框架中使用的一种简单而强大的发布/订阅协议。它允许客户端和服务器之间进行实时数据同步,是Meteor实现实时应用的核心技术之一。
DDP的主要特点
- 传输层灵活性: DDP可以基于WebSocket,也可以通过HTTP长轮询等方式实现,例如使用SockJS在不支持WebSocket的环境中工作。
- JSON格式: 所有的消息都使用JSON格式,便于解析和调试。-需要注意的是,实际的传输是用的EJSON进行序列化和反序列,从而支持了更多的对象传输,详参考 支持自定义对象序列化的EJSON介绍
- 发布/订阅模型: 允许客户端订阅服务器端的数据集,并在数据变化时接收更新。
- 方法调用: 客户端可以调用服务器端的方法,实现远程过程调用(RPC)。基于它的应用例子见文章 RPC方法注册及调用
- 实时更新: 当订阅的数据发生变化时,服务器会自动将更新推送给客户端。这部分是和发布订阅关联的,本文会涉及到底层实现
- 会话管理: 使用会话ID来维护客户端和服务器之间的连接状态。
DDP协议的详细过程
1. 握手和连接建立
- 客户端发送
connect
消息,可能包含版本信息和会话ID(如果是重连)。 - 服务器回复
connected
消息,包含新的会话ID。 - 如果是重连,服务器会恢复之前的订阅和方法调用状态。
2. 保活和心跳机制
- 客户端定期(通常每45秒)发送
ping
消息。 - 服务器回复
pong
消息。 - 如果超时未收到
pong
,客户端可能会尝试重新连接。
3. 方法调用
- 客户端发送
method
消息,包含方法名和参数。 - 服务器执行方法,可能会触发数据变更。
- 服务器发送
result
消息,包含方法执行结果或错误信息。 - 如果方法导致数据变更,服务器会发送相应的
added
、changed
或removed
消息。
4. 发布和订阅
- 客户端发送
sub
消息,包含订阅名称和参数。 - 服务器开始发送相关数据:
added
消息用于新增的文档changed
消息用于更新的文档removed
消息用于删除的文档
- 服务器发送
ready
消息,表示初始数据集已发送完毕。 - 之后,服务器会持续发送
added
、changed
和removed
消息以保持数据同步。 - 客户端可以发送
unsub
消息来取消订阅。
DDP消息类型详解
connect: 客户端发起连接请求
{ "msg": "connect", "version": "1", "support": ["1", "pre2", "pre1"]}
connected: 服务器确认连接成功
{ "msg": "connected", "session": "RandomSessionId123"}
ping/pong: 心跳消息
{ "msg": "ping", "id": "unique-id-123"} { "msg": "pong", "id": "unique-id-123"}
sub/unsub: 订阅和取消订阅
{ "msg": "sub", "id": "random-id", "name": "publicationName", "params": []} { "msg": "unsub", "id": "random-id"}
added/changed/removed: 数据更新通知
{ "msg": "added", "collection": "collectionName", "id": "documentId", "fields": { }} { "msg": "changed", "collection": "collectionName", "id": "documentId", "fields": { }} { "msg": "removed", "collection": "collectionName", "id": "documentId"}
ready: 初始数据加载完成通知
{ "msg": "ready", "subs": ["subscription-id-1", "subscription-id-2"]}
method/result: 方法调用和结果
{ "msg": "method", "method": "methodName", "params": [], "id": "call-id"} { "msg": "result", "id": "call-id", "result": { } }
DDP全生命周期时序图
可使用mermaid进行预览,时序图code如下
sequenceDiagram participant Client participant Server %% 握手和连接建立 Client->>Server: connect {version: "1", support: ["1", "pre2", "pre1"]} Server-->>Client: connected {session: "RandomSessionId123"} %% 发布订阅 Client->>Server: sub {id: "sub1", name: "posts", params: []} Server-->>Client: added {collection: "posts", id: "post1", fields: {...}} Server-->>Client: added {collection: "posts", id: "post2", fields: {...}} Server-->>Client: ready {subs: ["sub1"]} %% 实时更新 loop Real-time updates Server-->>Client: changed {collection: "posts", id: "post1", fields: {...}} Server-->>Client: added {collection: "posts", id: "post3", fields: {...}} Server-->>Client: removed {collection: "posts", id: "post2"} end %% 方法调用 Client->>Server: method {method: "addPost", params: [...], id: "m1"} Server-->>Client: added {collection: "posts", id: "post4", fields: {...}} Server-->>Client: result {id: "m1", result: {...}} %% 取消订阅 Client->>Server: unsub {id: "sub1"} %% 心跳机制 loop Keep-alive Client->>Server: ping {id: "ping1"} Server-->>Client: pong {id: "ping1"} end
时序图预览
DDP在Meteor中的应用
- 实时数据同步: 当服务器端的数据发生变化时,客户端可以立即收到更新。
- 用户界面响应: 通过DDP,用户界面可以实时反映数据的变化,提供流畅的用户体验。
- 分布式计算: 客户端可以调用服务器端的方法,实现复杂的计算或数据处理。
- 多客户端协作: 多个客户端可以同时订阅相同的数据集,实现实时协作功能。
- 离线支持: 通过本地缓存和重连机制,DDP可以支持离线操作和数据同步。
总结
DDP协议为实时Web应用提供了强大而灵活的数据同步机制,通过使用DDP,开发者可以轻松构建响应迅速、实时更新的现代Web应用,同时保持了在不同网络环境下的适应性。利用ddp开发一个后端作为转发中心,就可以实现多端+数据库之间的数据同步。