DolphinDB WebSocket接入:实时数据流

目录

    • 摘要
    • 一、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接入:

  1. WebSocket原理:全双工、实时推送、长连接
  2. 连接管理:创建连接、配置参数
  3. 数据接收:连接、发送、批量发送
  4. 消息处理:消息格式、处理函数
  5. 心跳保活:心跳机制、响应处理
  6. 断线重连:自动重连、数据缓冲

思考题:

  1. WebSocket相比HTTP有什么优势?
  2. 如何设计可靠的WebSocket连接?
  3. 如何处理WebSocket断线问题?

参考资料


相关推荐
虎头金猫5 天前
4K 视频总卡在公网带宽?用 N1 + OpenList 把网盘播放链路重新理顺
运维·服务器·网络·python·容器·beautifulsoup·pandas
只睡四小时5 天前
Canvas 弹道联机实战:700 行 + 固定时间步长
python·websocket·html5·游戏开发·canvas
wuyk5555 天前
《WiFi 嵌入式物联网开发全套实战》| 第 16 章 ESP32 AP+STA 双模共存原理与工程坑点
网络·stm32·物联网
XUEYUAN52125 天前
ASN 自治系统号风控:平台如何通过 IP 所属自治域批量识别代理流量
python·网络协议·http·网络安全·socks5
QYRdata5 天前
年均增速24.2%!机器人数据湖未来六年增长动能强劲
网络·机器人·服务发现
CHENKONG_CK5 天前
破解制鞋打磨痛点:RFID赋能去毛刺工序自动化升级
网络·单片机·嵌入式硬件·网络协议·tcp/ip
chshang19925 天前
工业路由器是什么?浅谈5G工业网络中的IR602
网络·物联网·5g·智能路由器
萧瑟余晖5 天前
Netty 核心组件与 Reactor 模型详解
网络·架构
ITxiaobing20235 天前
IP 定位服务选型指南:从准确率到工程落地的技术考察
linux·服务器·网络
wuyk5555 天前
【Socket 进阶之路】第 9 章 Linux 网络服务量产稳定性优化|心跳保活、TIME_WAIT、SO_LINGER、内存池、断线重连、完整异常防护框架
linux·服务器·开发语言·网络·物联网