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

分类:11.客户端与连接器 | 篇章:06 Node.js/C# 连接器
在这里插入图片描述
详情

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

速查表

维度Node.jsC#
包名@tdengine/websocketTDengine.Connector
协议WebSocket / RESTNative / WebSocket / REST
异步async/awaitasync/await
ORMTypeORM 等(视支持)EF Core(视支持)

Node.js 连接器详解

1. 安装

# WebSocket(推荐)
npm install @tdengine/websocket

# REST
npm install @tdengine/rest

2. 基本用法

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 高性能写入

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 订阅

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 集成示例

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. 安装

# .NET CLI
dotnet add package TDengine.Connector

7. 基本用法

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 与订阅

// 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 网关

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 服务

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.jsC#
单条 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 提供实时分析、可视化、事件管理与报警等功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TDengine (老段)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值