目录
-
- 摘要
- 一、WebSocket概述
-
- [1.1 什么是WebSocket](#1.1 什么是WebSocket)
- [1.2 WebSocket vs HTTP](#1.2 WebSocket vs HTTP)
- [1.3 适用场景](#1.3 适用场景)
- [二、DolphinDB WebSocket](#二、DolphinDB WebSocket)
-
- [2.1 创建WebSocket服务](#2.1 创建WebSocket服务)
- [2.2 连接管理](#2.2 连接管理)
- 三、实时数据接收
-
- [3.1 连接WebSocket](#3.1 连接WebSocket)
- [3.2 发送数据](#3.2 发送数据)
- [3.3 批量发送](#3.3 批量发送)
- 四、消息处理
-
- [4.1 消息格式](#4.1 消息格式)
- [4.2 消息处理函数](#4.2 消息处理函数)
- 五、心跳保活
-
- [5.1 心跳机制](#5.1 心跳机制)
- [5.2 服务端心跳响应](#5.2 服务端心跳响应)
- 六、断线重连
-
- [6.1 自动重连](#6.1 自动重连)
- [6.2 数据缓冲](#6.2 数据缓冲)
- 七、实战案例
-
- [7.1 实时监控数据推送](#7.1 实时监控数据推送)
- 八、总结
- 参考资料
摘要
本文深入讲解DolphinDB WebSocket接入技术。从WebSocket协议原理到连接管理,从实时数据接收到消息处理,从心跳保活到断线重连,全面介绍WebSocket数据接入的核心方法。通过丰富的代码示例,帮助读者掌握实时数据流处理的核心技能。
一、WebSocket概述
1.1 什么是WebSocket
WebSocket是全双工实时通信协议:
#mermaid-svg-Ultmphfbe6oaaeZL{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Ultmphfbe6oaaeZL .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Ultmphfbe6oaaeZL .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Ultmphfbe6oaaeZL .error-icon{fill:#552222;}#mermaid-svg-Ultmphfbe6oaaeZL .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Ultmphfbe6oaaeZL .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Ultmphfbe6oaaeZL .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Ultmphfbe6oaaeZL .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Ultmphfbe6oaaeZL .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Ultmphfbe6oaaeZL .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Ultmphfbe6oaaeZL .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Ultmphfbe6oaaeZL .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Ultmphfbe6oaaeZL .marker.cross{stroke:#333333;}#mermaid-svg-Ultmphfbe6oaaeZL svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Ultmphfbe6oaaeZL p{margin:0;}#mermaid-svg-Ultmphfbe6oaaeZL .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Ultmphfbe6oaaeZL .cluster-label text{fill:#333;}#mermaid-svg-Ultmphfbe6oaaeZL .cluster-label span{color:#333;}#mermaid-svg-Ultmphfbe6oaaeZL .cluster-label span p{background-color:transparent;}#mermaid-svg-Ultmphfbe6oaaeZL .label text,#mermaid-svg-Ultmphfbe6oaaeZL span{fill:#333;color:#333;}#mermaid-svg-Ultmphfbe6oaaeZL .node rect,#mermaid-svg-Ultmphfbe6oaaeZL .node circle,#mermaid-svg-Ultmphfbe6oaaeZL .node ellipse,#mermaid-svg-Ultmphfbe6oaaeZL .node polygon,#mermaid-svg-Ultmphfbe6oaaeZL .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Ultmphfbe6oaaeZL .rough-node .label text,#mermaid-svg-Ultmphfbe6oaaeZL .node .label text,#mermaid-svg-Ultmphfbe6oaaeZL .image-shape .label,#mermaid-svg-Ultmphfbe6oaaeZL .icon-shape .label{text-anchor:middle;}#mermaid-svg-Ultmphfbe6oaaeZL .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Ultmphfbe6oaaeZL .rough-node .label,#mermaid-svg-Ultmphfbe6oaaeZL .node .label,#mermaid-svg-Ultmphfbe6oaaeZL .image-shape .label,#mermaid-svg-Ultmphfbe6oaaeZL .icon-shape .label{text-align:center;}#mermaid-svg-Ultmphfbe6oaaeZL .node.clickable{cursor:pointer;}#mermaid-svg-Ultmphfbe6oaaeZL .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Ultmphfbe6oaaeZL .arrowheadPath{fill:#333333;}#mermaid-svg-Ultmphfbe6oaaeZL .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Ultmphfbe6oaaeZL .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Ultmphfbe6oaaeZL .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Ultmphfbe6oaaeZL .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Ultmphfbe6oaaeZL .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Ultmphfbe6oaaeZL .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Ultmphfbe6oaaeZL .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Ultmphfbe6oaaeZL .cluster text{fill:#333;}#mermaid-svg-Ultmphfbe6oaaeZL .cluster span{color:#333;}#mermaid-svg-Ultmphfbe6oaaeZL div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Ultmphfbe6oaaeZL .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Ultmphfbe6oaaeZL rect.text{fill:none;stroke-width:0;}#mermaid-svg-Ultmphfbe6oaaeZL .icon-shape,#mermaid-svg-Ultmphfbe6oaaeZL .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Ultmphfbe6oaaeZL .icon-shape p,#mermaid-svg-Ultmphfbe6oaaeZL .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Ultmphfbe6oaaeZL .icon-shape .label rect,#mermaid-svg-Ultmphfbe6oaaeZL .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Ultmphfbe6oaaeZL .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Ultmphfbe6oaaeZL .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Ultmphfbe6oaaeZL :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} WebSocket架构
客户端
WebSocket连接
服务端
DolphinDB
特点
全双工
实时推送
长连接
1.2 WebSocket vs HTTP
| 特性 | HTTP | WebSocket |
|---|---|---|
| 通信方式 | 半双工 | 全双工 |
| 连接 | 短连接 | 长连接 |
| 实时性 | 轮询 | 实时推送 |
| 开销 | 高 | 低 |
1.3 适用场景
| 场景 | 说明 |
|---|---|
| 实时监控 | 实时数据推送 |
| 告警通知 | 实时告警推送 |
| 仪表盘 | 实时数据展示 |
| 设备控制 | 实时指令下发 |
二、DolphinDB WebSocket
2.1 创建WebSocket服务
python
// 创建WebSocket服务
// DolphinDB内置WebSocket支持
// 创建流表接收数据
share streamTable(1:0,
`device_id`timestamp`temperature`humidity,
[SYMBOL, TIMESTAMP, DOUBLE, DOUBLE]) as ws_stream
// WebSocket端点
// ws://localhost:8848/ws
2.2 连接管理
python
// WebSocket连接配置
config = dict(STRING, ANY, [
["maxConnections", 1000],
["heartbeatInterval", 30000],
["maxMessageSize", 1048576]
])
三、实时数据接收
3.1 连接WebSocket
javascript
// JavaScript客户端示例
const ws = new WebSocket('ws://localhost:8848/ws');
ws.onopen = function() {
console.log('WebSocket连接成功');
// 订阅主题
ws.send(JSON.stringify({
action: 'subscribe',
topic: 'sensor/data'
}));
};
ws.onmessage = function(event) {
const data = JSON.parse(event.data);
console.log('收到数据:', data);
};
ws.onerror = function(error) {
console.error('WebSocket错误:', error);
};
ws.onclose = function() {
console.log('WebSocket连接关闭');
};
3.2 发送数据
javascript
// 发送数据到DolphinDB
function sendData(data) {
ws.send(JSON.stringify({
action: 'write',
table: 'ws_stream',
data: data
}));
}
// 示例
sendData({
device_id: 'D001',
timestamp: new Date().toISOString(),
temperature: 25.5,
humidity: 50.0
});
3.3 批量发送
javascript
// 批量发送数据
function sendBatch(dataList) {
ws.send(JSON.stringify({
action: 'write',
table: 'ws_stream',
data: dataList
}));
}
// 示例
const batch = [];
for (let i = 0; i < 100; i++) {
batch.push({
device_id: `D${i.toString().padStart(3, '0')}`,
timestamp: new Date().toISOString(),
temperature: 20 + Math.random() * 10,
humidity: 40 + Math.random() * 20
});
}
sendBatch(batch);
四、消息处理
4.1 消息格式
python
// JSON消息格式
{
"action": "write", // 操作类型
"table": "ws_stream", // 目标表
"data": { // 数据
"device_id": "D001",
"timestamp": "2024-01-01T00:00:00",
"temperature": 25.5,
"humidity": 50.0
}
}
// 订阅消息
{
"action": "subscribe",
"topic": "sensor/data"
}
// 查询消息
{
"action": "query",
"sql": "select * from ws_stream limit 10"
}
4.2 消息处理函数
python
// 消息处理函数
def handleWsMessage(msg) {
action = msg.action
if (action == "write") {
// 写入数据
table = msg.table
data = msg.data
// 写入逻辑
} else if (action == "subscribe") {
// 订阅主题
topic = msg.topic
// 订阅逻辑
} else if (action == "query") {
// 查询数据
sql = msg.sql
// 查询逻辑
}
}
五、心跳保活
5.1 心跳机制
javascript
// 客户端心跳
let heartbeatInterval;
function startHeartbeat() {
heartbeatInterval = setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ action: 'ping' }));
}
}, 30000); // 每30秒发送心跳
}
function stopHeartbeat() {
clearInterval(heartbeatInterval);
}
ws.onopen = function() {
startHeartbeat();
};
ws.onclose = function() {
stopHeartbeat();
};
5.2 服务端心跳响应
python
// 服务端心跳处理
def handleHeartbeat(conn) {
// 收到ping,返回pong
ws::send(conn, {action: "pong", timestamp: now()})
}
六、断线重连
6.1 自动重连
javascript
// 自动重连机制
let ws;
let reconnectAttempts = 0;
const maxReconnectAttempts = 5;
function connect() {
ws = new WebSocket('ws://localhost:8848/ws');
ws.onopen = function() {
console.log('WebSocket连接成功');
reconnectAttempts = 0;
};
ws.onclose = function() {
console.log('WebSocket连接关闭');
if (reconnectAttempts < maxReconnectAttempts) {
reconnectAttempts++;
console.log(`尝试重连 (${reconnectAttempts}/${maxReconnectAttempts})`);
setTimeout(connect, 3000);
}
};
ws.onerror = function(error) {
console.error('WebSocket错误:', error);
};
}
connect();
6.2 数据缓冲
javascript
// 断线时缓冲数据
const dataBuffer = [];
const maxBufferSize = 10000;
function sendDataWithBuffer(data) {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify(data));
// 发送缓冲数据
while (dataBuffer.length > 0) {
ws.send(JSON.stringify(dataBuffer.shift()));
}
} else {
// 缓冲数据
if (dataBuffer.length < maxBufferSize) {
dataBuffer.push(data);
}
}
}
七、实战案例
7.1 实时监控数据推送
python
// ========== 实时监控数据推送 ==========
// 1. 创建流表
share streamTable(100000:0,
`device_id`timestamp`temperature`humidity`pressure,
[SYMBOL, TIMESTAMP, DOUBLE, DOUBLE, DOUBLE]) as monitor_stream
// 2. 启用持久化
enableTablePersistence(monitor_stream, true, true, 1000000)
// 3. 创建分布式表
db = database("dfs://ws_db", VALUE, 1..1000)
schema = table(1:0, `device_id`timestamp`temperature`humidity`pressure,
[SYMBOL, TIMESTAMP, DOUBLE, DOUBLE, DOUBLE])
db.createPartitionedTable(schema, `monitor_data, `device_id)
// 4. 订阅写入
subscribeTable(, "monitor_stream", "persist", -1,
def(msg) {
loadTable("dfs://ws_db", "monitor_data").append!(msg)
}, 10000, 5000)
// 5. WebSocket端点
// ws://localhost:8848/ws
// 6. 客户端示例(JavaScript)
/*
const ws = new WebSocket('ws://localhost:8848/ws');
ws.onopen = function() {
console.log('连接成功');
};
function pushData(deviceId, temp, humid, press) {
ws.send(JSON.stringify({
action: 'write',
table: 'monitor_stream',
data: {
device_id: deviceId,
timestamp: new Date().toISOString(),
temperature: temp,
humidity: humid,
pressure: press
}
}));
}
*/
print("实时监控数据推送系统已就绪")
八、总结
本文详细介绍了DolphinDB WebSocket接入:
- WebSocket原理:全双工、实时推送、长连接
- 连接管理:创建连接、配置参数
- 数据接收:连接、发送、批量发送
- 消息处理:消息格式、处理函数
- 心跳保活:心跳机制、响应处理
- 断线重连:自动重连、数据缓冲
思考题:
- WebSocket相比HTTP有什么优势?
- 如何设计可靠的WebSocket连接?
- 如何处理WebSocket断线问题?