TDengine Node.js 与 C# 连接器 — Web 服务与 .NET 集成

分类 :11.客户端与连接器 | 篇章 :06 Node.js/C# 连接器

详情

Node.js 适合后端 Web 服务与 IoT 网关,C# 适合 .NET 企业应用与 Windows 工业环境。本文统一讲解两者用法。

速查表

维度 Node.js C#
包名 @tdengine/websocket TDengine.Connector
协议 WebSocket / REST Native / WebSocket / REST
异步 async/await async/await
ORM TypeORM 等(视支持) EF Core(视支持)

Node.js 连接器详解

1. 安装

bash 复制代码
# WebSocket(推荐)
npm install @tdengine/websocket

# REST
npm install @tdengine/rest

2. 基本用法

javascript 复制代码
const taos = require("@tdengine/websocket");

async function main() {
  const conn = await taos.sqlConnect({
    url: "ws://localhost:6041",
    user: "root",
    password: "taosdata",
    db: "test"
  });
  
  // DDL
  await conn.exec("CREATE DATABASE IF NOT EXISTS test");
  await conn.exec("USE test");
  await conn.exec(`
    CREATE STABLE IF NOT EXISTS meters (
      ts TIMESTAMP, current FLOAT, voltage INT
    ) TAGS (location VARCHAR(32))
  `);
  
  // INSERT
  await conn.exec(`
    INSERT INTO d001 USING meters TAGS('Beijing') 
    VALUES (NOW, 25.3, 220)
  `);
  
  // SELECT
  const result = await conn.query("SELECT * FROM meters LIMIT 10");
  const meta = result.getMeta();
  console.log("Columns:", meta);
  
  while (await result.next()) {
    const row = result.getData();
    console.log(row);
  }
  
  await conn.close();
}

main().catch(console.error);

3. STMT2 高性能写入

javascript 复制代码
const stmt = await conn.statement();
await stmt.prepare("INSERT INTO ? USING meters TAGS(?) VALUES(?, ?, ?)");

// 多子表绑定
const tables = ["d001", "d002"];
const tags = [["Beijing"], ["Shanghai"]];
const data = [
  // d001 的数据
  {
    ts: [Date.now(), Date.now() + 1000],
    current: [25.3, 25.8],
    voltage: [220, 221]
  },
  // d002 的数据
  {
    ts: [Date.now(), Date.now() + 1000],
    current: [26.5, 27.1],
    voltage: [218, 219]
  }
];

for (let i = 0; i < tables.length; i++) {
  stmt.setTableName(tables[i]);
  stmt.setTags(tags[i]);
  stmt.bindParam(data[i]);
}

await stmt.execute();
await stmt.close();

4. TMQ 订阅

javascript 复制代码
const { TMQConsumer } = require("@tdengine/websocket");

const consumer = new TMQConsumer({
  url: "ws://localhost:6041",
  user: "root",
  password: "taosdata",
  "group.id": "my_group",
  "auto.offset.reset": "earliest"
});

await consumer.subscribe(["my_topic"]);

while (true) {
  const messages = await consumer.poll(1000);
  for (const msg of messages) {
    console.log(msg);
  }
  await consumer.commit();
}

5. Express 集成示例

javascript 复制代码
const express = require("express");
const taos = require("@tdengine/websocket");

const app = express();
app.use(express.json());

let conn;

app.listen(3000, async () => {
  conn = await taos.sqlConnect({
    url: "ws://localhost:6041",
    user: "root",
    password: "taosdata",
    db: "iot"
  });
  console.log("Server started on 3000");
});

app.get("/api/devices/:id/recent", async (req, res) => {
  const result = await conn.query(
    `SELECT * FROM ${req.params.id} WHERE ts > NOW - 1h LIMIT 100`
  );
  const rows = [];
  while (await result.next()) {
    rows.push(result.getData());
  }
  res.json(rows);
});

app.post("/api/devices/:id", async (req, res) => {
  const { current, voltage } = req.body;
  await conn.exec(
    `INSERT INTO ${req.params.id} VALUES (NOW, ${current}, ${voltage})`
  );
  res.status(201).json({ ok: true });
});

C# 连接器详解

6. 安装

bash 复制代码
# .NET CLI
dotnet add package TDengine.Connector

7. 基本用法

csharp 复制代码
using TDengine.Driver;
using TDengine.Driver.Client;

class Program
{
    static void Main()
    {
        // WebSocket
        var builder = new ConnectionStringBuilder(
            "protocol=WebSocket;host=localhost;port=6041;" +
            "user=root;password=taosdata;db=test"
        );
        using var client = DbDriver.Open(builder);
        
        // DDL
        client.Exec("CREATE DATABASE IF NOT EXISTS test");
        client.Exec("USE test");
        client.Exec(@"
          CREATE STABLE IF NOT EXISTS meters (
            ts TIMESTAMP, current FLOAT, voltage INT
          ) TAGS (location VARCHAR(32))
        ");
        
        // INSERT
        client.Exec(
          "INSERT INTO d001 USING meters TAGS('Beijing') " +
          "VALUES (NOW, 25.3, 220)"
        );
        
        // SELECT
        using var rows = client.Query("SELECT * FROM meters LIMIT 10");
        while (rows.Read())
        {
            for (int i = 0; i < rows.FieldCount; i++)
            {
                Console.Write(rows.GetValue(i) + " ");
            }
            Console.WriteLine();
        }
    }
}

8. STMT2 与订阅

csharp 复制代码
// STMT2
using var stmt = client.StmtInit();
stmt.Prepare("INSERT INTO ? USING meters TAGS(?) VALUES(?, ?, ?)");

stmt.SetTableName("d001");
stmt.SetTags(new object[] { "Beijing" });

// 批量数据
var tsArr = new long[1000];
var currentArr = new float[1000];
var voltageArr = new int[1000];
for (int i = 0; i < 1000; i++)
{
    tsArr[i] = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() + i;
    currentArr[i] = 25.0f + i * 0.01f;
    voltageArr[i] = 220;
}

stmt.BindColumn(0, tsArr);
stmt.BindColumn(1, currentArr);
stmt.BindColumn(2, voltageArr);
stmt.AddBatch();
stmt.Execute();


// TMQ
using TDengine.TMQ;

var consumerConfig = new Dictionary<string, string>
{
    { "td.connect.ip", "localhost" },
    { "td.connect.user", "root" },
    { "td.connect.pass", "taosdata" },
    { "group.id", "my_group" },
    { "auto.offset.reset", "earliest" }
};

using var consumer = new ConsumerBuilder<Dictionary<string, object>>(
    consumerConfig).Build();
consumer.Subscribe(new[] { "my_topic" });

while (true)
{
    var cr = consumer.Consume(1000);
    if (cr == null) continue;
    
    Console.WriteLine(cr.Message.Value);
    consumer.Commit(cr);
}

代码示例

Node.js IoT 网关

javascript 复制代码
const mqtt = require("mqtt");
const taos = require("@tdengine/websocket");

const tdConn = await taos.sqlConnect({
  url: "ws://localhost:6041",
  user: "root",
  password: "taosdata",
  db: "iot"
});

const mqttClient = mqtt.connect("mqtt://broker:1883");
mqttClient.subscribe("sensors/+/data");

const buffer = [];
const FLUSH_INTERVAL = 1000;
const FLUSH_SIZE = 1000;

mqttClient.on("message", (topic, msg) => {
  const device = topic.split("/")[1];
  const data = JSON.parse(msg);
  buffer.push({ device, ...data });
  
  if (buffer.length >= FLUSH_SIZE) {
    flush();
  }
});

setInterval(flush, FLUSH_INTERVAL);

async function flush() {
  if (buffer.length === 0) return;
  const batch = buffer.splice(0, buffer.length);
  
  // 批量写入(用 STMT2 性能更好)
  for (const item of batch) {
    await tdConn.exec(
      `INSERT INTO ${item.device} VALUES ` +
      `(${item.ts}, ${item.value}, ${item.status})`
    );
  }
}

C# Windows 服务

csharp 复制代码
public class IoTService : BackgroundService
{
    private readonly ITaosClient _client;
    
    protected override async Task ExecuteAsync(
        CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            var data = await ReadFromPLC();
            _client.Exec($"INSERT INTO {data.Device} VALUES " +
                        $"(NOW, {data.Value})");
            
            await Task.Delay(1000, stoppingToken);
        }
    }
}

性能考量

性能对比

操作 Node.js C#
单条 exec 几千/秒 上万/秒
批量 STMT2 几十万行/秒 上百万行/秒
异步并发
内存占用

最佳实践

语言 建议
Node.js 长连接 + 批量缓冲
C# using 显式释放
两者 用 STMT2 替代单条 INSERT

FAQ

Q1: Node.js 浏览器能用吗?

@tdengine/websocket 只能服务端 Node.js。浏览器需用 @tdengine/rest 或自行 WS 实现。

Q2: TypeScript 支持?

两个包都自带 .d.ts 类型定义。

Q3: C# .NET Framework vs Core?

支持 .NET Standard 2.0+,可在 .NET Framework 4.6.1+ 和 .NET Core / .NET 5+ 使用。

Q4: EF Core 集成?

官方暂无 EF Core Provider,需直接用 ADO.NET 接口或自定义 Provider。

Q5: Windows 部署注意?

  • Native 需 taos.dll
  • WebSocket 无依赖
  • 防火墙开放 6041

参考

系统构架篇

数据模型

存储引擎

查询引擎

数据写入

数据订阅

预聚合

索引

SQL 语句

客户端与连接器

关于 TDengine

TDengine 专为物联网IoT平台、工业大数据平台设计。其中,TDengine TSDB 是一款高性能、分布式的时序数据库(Time Series Database),同时它还带有内建的缓存、流式计算、数据订阅等系统功能;TDengine IDMP 是一款AI原生工业数据管理平台,它通过树状层次结构建立数据目录,对数据进行标准化、情景化,并通过 AI 提供实时分析、可视化、事件管理与报警等功能。

相关推荐
l1t1 小时前
PostgreSQL 11–18 中的 SQL 改进:个人精选-1
数据库·sql·postgresql
逃跑的浣熊2 小时前
MySQL 性能分析报告:Page Cache 与 fsync 对读写性能的影响
数据库
路由侠内网穿透.2 小时前
本地部署开源日志收集系统 Log Bull 并实现外部访问
运维·服务器·网络·数据库·开源
河西石头2 小时前
再谈C#的抽象类和接口:从“适配器”到“毛坯房”的设计哲学
开发语言·c#·接口·依赖注入·抽象类·依赖倒挂
颜x小2 小时前
[C#]——接口与继承
开发语言·c++·c#
码云数智-大飞3 小时前
PHP 大文件上传、断点续传完整实现思路
数据库
莉莉周的成长实验室3 小时前
2026年七夕海报用什么AI工具可以做?品牌运营实测3个高频场景
大数据·人工智能
sevenll073 小时前
SqlKit - 覆盖 50+ 数据库的 AI 智能体 SQL 桌面客户端
数据库·人工智能·sql·智能体
宸津-代码粉碎机3 小时前
告别手动Jar部署!生产级无损热部署方案,彻底解决OOM与更新失效问题
java·大数据·开发语言·人工智能·python