
TDengine C/C++ 连接器入门指南
概述
TDengine C/C++ 连接器是 TDengine 提供的官方客户端驱动程序,允许 C/C++ 开发人员连接 TDengine 集群并进行数据存储、查询等操作。本指南将帮助您快速上手 C/C++ 连接器的使用。
前置条件
在开始之前,请确保:
- 已安装 TDengine :需要安装 TDengine 客户端或服务端
- 开发环境:支持 C/C++ 开发的编译器(GCC、Clang、MSVC 等)
- 操作系统:Linux、Windows 或 macOS
第一步:安装和配置
1.1 安装 TDengine 客户端
根据您的操作系统,安装相应的 TDengine 客户端:
Linux (Ubuntu/Debian)
bash
wget https://www.taosdata.com/assets-download/3.0/TDengine-client-3.x.x.x-Linux-x64.tar.gz
tar -xzvf TDengine-client-3.x.x.x-Linux-x64.tar.gz
cd TDengine-client-3.x.x.x && sudo ./install_client.sh
Windows
- 下载并运行 TDengine 客户端安装程序
- 默认安装路径:
C:\TDengine
macOS
- 下载并运行 TDengine 客户端安装程序
- 默认安装路径:/usr/local/Cellar/tdengine (Cellar 名称随不同系统版本会变化)
1.2 验证安装
安装完成后,验证头文件和动态库的位置:
| 操作系统 | 头文件路径 | 动态库路径 |
|---|---|---|
| Linux | /usr/local/taos/include | /usr/local/taos/driver/libtaos.so |
| Windows | C:\TDengine\include | C:\TDengine\driver\taos.dll |
| macOS | /usr/local/include | /usr/local/lib/libtaos.dylib |
第二步:选择连接方式
TDengine 支持两种连接方式:
2.1 WebSocket 连接(推荐)
优点:
- 客户端和服务端版本无需完全匹配
- 性能接近原生连接
- 支持云服务和远程连接
使用场景:适合大多数应用场景,特别是云环境和跨版本场景
2.2 原生连接
优点:
- 功能最完整
- 直接通信,延迟略低
限制:
- 客户端和服务端版本需要严格匹配(强烈建议版本一致)
使用场景:局域网环境且版本可控时
第三步:编写第一个程序
3.1 创建项目目录
bash
mkdir tdengine_demo
cd tdengine_demo
3.2 编写代码(WebSocket 连接)
创建文件 demo.c:
c
#include <stdio.h>
#include <stdlib.h>
#include "taos.h"
int main() {
// 1. 初始化环境(可选,taos_connect 会自动调用)
taos_init();
// 2. 设置连接方式为 WebSocket(必须在程序开始时调用一次)
taos_options(TSDB_OPTION_DRIVER, "websocket");
// 3. 连接到 TDengine
TAOS *taos = taos_connect(
"localhost", // 主机地址
"root", // 用户名
"taosdata", // 密码
NULL, // 数据库名(可选)
0 // 端口,0 表示使用默认端口(WebSocket 为 6041)
);
// 4. 检查连接是否成功
if (taos == NULL) {
printf("连接失败:%s\n", taos_errstr(NULL));
return -1;
}
printf("连接成功!\n");
printf("客户端版本:%s\n", taos_get_client_info());
printf("服务端版本:%s\n", taos_get_server_info(taos));
// 5. 创建数据库
TAOS_RES *res = taos_query(taos, "CREATE DATABASE IF NOT EXISTS test");
if (taos_errno(res) != 0) {
printf("创建数据库失败:%s\n", taos_errstr(res));
taos_free_result(res);
taos_close(taos);
return -1;
}
printf("数据库创建成功!\n");
taos_free_result(res);
// 6. 使用数据库
res = taos_query(taos, "USE test");
if (taos_errno(res) != 0) {
printf("使用数据库失败:%s\n", taos_errstr(res));
taos_free_result(res);
taos_close(taos);
return -1;
}
taos_free_result(res);
// 7. 创建超级表
res = taos_query(taos,
"CREATE STABLE IF NOT EXISTS meters "
"(ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) "
"TAGS (location BINARY(64), groupId INT)"
);
if (taos_errno(res) != 0) {
printf("创建超级表失败:%s\n", taos_errstr(res));
taos_free_result(res);
taos_close(taos);
return -1;
}
printf("超级表创建成功!\n");
taos_free_result(res);
// 8. 插入数据
res = taos_query(taos,
"INSERT INTO d1001 USING meters TAGS('Beijing.Chaoyang', 1) "
"VALUES (NOW, 10.2, 219, 0.32)"
);
if (taos_errno(res) != 0) {
printf("插入数据失败:%s\n", taos_errstr(res));
} else {
printf("成功插入 %d 行数据\n", taos_affected_rows(res));
}
taos_free_result(res);
// 9. 查询数据
res = taos_query(taos, "SELECT * FROM meters");
if (taos_errno(res) != 0) {
printf("查询失败:%s\n", taos_errstr(res));
taos_free_result(res);
taos_close(taos);
return -1;
}
// 10. 获取字段信息
int num_fields = taos_num_fields(res);
TAOS_FIELD *fields = taos_fetch_fields(res);
// 打印表头
for (int i = 0; i < num_fields; i++) {
printf("%s\t", fields[i].name);
}
printf("\n");
// 11. 逐行获取查询结果
TAOS_ROW row;
while ((row = taos_fetch_row(res))) {
int *lengths = taos_fetch_lengths(res);
for (int i = 0; i < num_fields; i++) {
if (row[i] == NULL) {
printf("NULL\t");
} else {
// 根据字段类型打印数据
switch (fields[i].type) {
case TSDB_DATA_TYPE_TIMESTAMP:
printf("%lld\t", *(int64_t *)row[i]);
break;
case TSDB_DATA_TYPE_INT:
printf("%d\t", *(int *)row[i]);
break;
case TSDB_DATA_TYPE_FLOAT:
printf("%.2f\t", *(float *)row[i]);
break;
case TSDB_DATA_TYPE_BINARY:
case TSDB_DATA_TYPE_NCHAR:
printf("%.*s\t", lengths[i], (char *)row[i]);
break;
default:
break;
}
}
}
printf("\n");
}
// 12. 释放结果集
taos_free_result(res);
// 13. 关闭连接
taos_close(taos);
// 14. 清理环境
taos_cleanup();
printf("程序执行完毕!\n");
return 0;
}
3.3 编写代码(原生连接)
如果您要使用原生连接,只需将 WebSocket 版本的第 2 步注释掉即可:
c
// 使用原生连接,不需要设置驱动类型
// taos_options(TSDB_OPTION_DRIVER, "websocket"); // 注释或删除此行
// 连接到 TDengine(使用默认原生端口 6030)
TAOS *taos = taos_connect(
"localhost",
"root",
"taosdata",
NULL,
0 // 0 表示使用默认端口(原生连接为 6030)
);
3.4 编译程序
Linux/macOS
bash
gcc demo.c -o demo -ltaos -I/usr/local/taos/include -L/usr/local/taos/driver
Windows (使用 MSVC)
cmd
cl demo.c /I C:\TDengine\include /link C:\TDengine\driver\taos.lib
Windows (使用 MinGW)
bash
gcc demo.c -o demo.exe -I C:/TDengine/include -L C:/TDengine/driver -ltaos
3.5 运行程序
Linux/macOS
bash
# 如果提示找不到动态库,需要设置 LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/usr/local/taos/driver:$LD_LIBRARY_PATH
./demo
Windows
cmd
demo.exe
预期输出
连接成功!
客户端版本:3.3.x.x
服务端版本:3.3.x.x
数据库创建成功!
超级表创建成功!
成功插入 1 行数据
ts current voltage phase location groupId
1704528000000 10.20 219 0.32 Beijing.Chaoyang 1
程序执行完毕!
第四步:核心概念理解
4.1 连接对象 (TAOS)
TAOS是数据库连接句柄,所有操作都基于此句柄- 通过
taos_connect()创建,使用完毕后必须调用taos_close()释放
4.2 结果集 (TAOS_RES)
TAOS_RES是执行 SQL 后返回的结果集- 无论是查询、插入还是 DDL 操作,都会返回结果集
- 使用完毕后必须调用
taos_free_result()释放
4.3 错误处理
TDengine 使用错误码机制:
c
TAOS_RES *res = taos_query(taos, sql);
// 检查是否出错
if (taos_errno(res) != 0) {
printf("错误码:%d\n", taos_errno(res));
printf("错误信息:%s\n", taos_errstr(res));
taos_free_result(res);
return -1;
}
重要 :不能通过 taos_query() 返回 NULL 来判断失败,必须使用 taos_errno() 检查错误码。
4.4 数据类型映射
| TDengine 类型 | C 类型 | 说明 |
|---|---|---|
| TIMESTAMP | int64_t | Unix 时间戳(毫秒/微秒/纳秒) |
| INT | int32_t | 32位整数 |
| BIGINT | int64_t | 64位整数 |
| FLOAT | float | 单精度浮点数 |
| DOUBLE | double | 双精度浮点数 |
| BINARY | char[] | 二进制字符串 |
| NCHAR | char[] (UTF-8) | Unicode 字符串 |
| BOOL | int8_t | 布尔值(0 或 1) |
| TINYINT | int8_t | 8位整数 |
| SMALLINT | int16_t | 16位整数 |
第五步:常见操作示例
5.1 批量插入数据
c
// 方式 1:多行 SQL 插入
const char *sql =
"INSERT INTO "
"d1001 USING meters TAGS('Beijing.Chaoyang', 1) VALUES (NOW, 10.2, 219, 0.32) "
"d1002 USING meters TAGS('Beijing.Haidian', 2) VALUES (NOW, 11.5, 220, 0.28) "
"d1003 USING meters TAGS('Shanghai.Pudong', 3) VALUES (NOW, 12.1, 221, 0.35)";
TAOS_RES *res = taos_query(taos, sql);
if (taos_errno(res) == 0) {
printf("成功插入 %d 行数据\n", taos_affected_rows(res));
}
taos_free_result(res);
5.2 聚合查询
c
const char *sql =
"SELECT location, AVG(current), MAX(voltage), MIN(phase) "
"FROM meters "
"WHERE ts >= NOW - 1h "
"GROUP BY location";
TAOS_RES *res = taos_query(taos, sql);
if (taos_errno(res) != 0) {
printf("查询失败:%s\n", taos_errstr(res));
taos_free_result(res);
return -1;
}
TAOS_ROW row;
while ((row = taos_fetch_row(res))) {
printf("位置:%s, 平均电流:%.2f, 最大电压:%d, 最小相位:%.2f\n",
(char *)row[0],
*(double *)row[1],
*(int *)row[2],
*(double *)row[3]);
}
taos_free_result(res);
5.3 数据订阅(流式处理)
c
#include "taos.h"
#include <stdio.h>
int main() {
taos_options(TSDB_OPTION_DRIVER, "websocket");
TAOS *taos = taos_connect("localhost", "root", "taosdata", "test", 0);
// 创建 topic
TAOS_RES *res = taos_query(taos,
"CREATE TOPIC IF NOT EXISTS topic_meters AS SELECT * FROM meters");
taos_free_result(res);
// 创建消费者
tmq_conf_t *conf = tmq_conf_new();
tmq_conf_set(conf, "group.id", "group1");
tmq_conf_set(conf, "td.connect.user", "root");
tmq_conf_set(conf, "td.connect.pass", "taosdata");
tmq_conf_set(conf, "auto.offset.reset", "earliest");
tmq_t *tmq = tmq_consumer_new(conf, NULL, 0);
tmq_conf_destroy(conf);
// 订阅 topic
tmq_list_t *topic_list = tmq_list_new();
tmq_list_append(topic_list, "topic_meters");
tmq_subscribe(tmq, topic_list);
tmq_list_destroy(topic_list);
// 消费数据
while (1) {
TAOS_RES *message = tmq_consumer_poll(tmq, 1000);
if (message) {
TAOS_ROW row;
while ((row = taos_fetch_row(message))) {
printf("收到新数据\n");
// 处理数据...
}
taos_free_result(message);
}
}
// 取消订阅并关闭
tmq_unsubscribe(tmq);
tmq_consumer_close(tmq);
taos_close(taos);
return 0;
}
第六步:最佳实践
6.1 连接管理
c
// 使用连接池(简单示例)
#define MAX_CONNECTIONS 10
TAOS *pool[MAX_CONNECTIONS];
void init_pool() {
for (int i = 0; i < MAX_CONNECTIONS; i++) {
pool[i] = taos_connect("localhost", "root", "taosdata", "test", 0);
}
}
void destroy_pool() {
for (int i = 0; i < MAX_CONNECTIONS; i++) {
if (pool[i]) taos_close(pool[i]);
}
}
6.2 错误处理模式
c
int execute_sql(TAOS *taos, const char *sql) {
TAOS_RES *res = taos_query(taos, sql);
int code = taos_errno(res);
if (code != 0) {
fprintf(stderr, "SQL 执行失败:%s\nSQL:%s\n",
taos_errstr(res), sql);
taos_free_result(res);
return -1;
}
int affected = taos_affected_rows(res);
taos_free_result(res);
return affected;
}
6.3 资源管理
必须释放的资源:
- 结果集:
taos_free_result(res) - 连接:
taos_close(taos) - 语句:
taos_stmt_close(stmt)
推荐使用 RAII 模式(C++):
cpp
class TaosConnection {
private:
TAOS *taos;
public:
TaosConnection(const char *host, const char *user,
const char *pass, const char *db) {
taos = taos_connect(host, user, pass, db, 0);
if (!taos) throw std::runtime_error(taos_errstr(NULL));
}
~TaosConnection() {
if (taos) taos_close(taos);
}
TAOS* get() { return taos; }
};
6.4 性能优化
- 批量操作:一次插入多行数据,而不是逐行插入
- 使用参数绑定:避免 SQL 拼接,提高性能和安全性
- 合理设置缓冲区 :使用
taos_fetch_block()批量获取数据 - 连接复用:避免频繁创建和销毁连接
c
// 使用 taos_fetch_block 批量获取
TAOS_RES *res = taos_query(taos, "SELECT * FROM meters");
TAOS_ROW *rows;
int num_rows;
while ((num_rows = taos_fetch_block(res, &rows)) > 0) {
for (int i = 0; i < num_rows; i++) {
// 处理 rows[i]
}
}
taos_free_result(res);
第七步:调试和故障排查
7.1 启用日志
c
// 设置日志级别
taos_options(TSDB_OPTION_DEBUGFLAG, "135"); // 135 = DEBUG 级别
7.2 常见问题
问题 1:找不到动态库
bash
# Linux/macOS
export LD_LIBRARY_PATH=/usr/local/taos/driver:$LD_LIBRARY_PATH
# Windows:将 C:\TDengine\driver 添加到系统 PATH
问题 2:连接失败
- 检查服务是否启动:
systemctl status taosd(Linux) - 检查端口是否开放:WebSocket 6041,原生连接 6030
- 检查防火墙设置
问题 3:版本不匹配(原生连接)
- 确保客户端和服务端版本一致
- 或改用 WebSocket 连接方式
问题 4:字符编码问题
c
// 设置字符集为 UTF-8
taos_options(TSDB_OPTION_CHARSET, "UTF-8");
7.3 性能分析
c
#include <time.h>
clock_t start = clock();
TAOS_RES *res = taos_query(taos, sql);
clock_t end = clock();
double elapsed = (double)(end - start) / CLOCKS_PER_SEC;
printf("SQL 执行耗时:%.3f 秒\n", elapsed);
taos_free_result(res);
第八步:进阶主题
8.1 使用 CMake 构建项目
创建 CMakeLists.txt:
cmake
cmake_minimum_required(VERSION 3.10)
project(TDengineDemo C)
set(CMAKE_C_STANDARD 11)
# 查找 TDengine 库
find_library(TAOS_LIBRARY taos
PATHS /usr/local/taos/driver /usr/local/lib
)
if(NOT TAOS_LIBRARY)
message(FATAL_ERROR "TDengine library not found")
endif()
# 设置头文件路径
include_directories(/usr/local/taos/include)
# 添加可执行文件
add_executable(demo demo.c)
# 链接 TDengine 库
target_link_libraries(demo ${TAOS_LIBRARY})
构建:
bash
mkdir build && cd build
cmake ..
make
./demo
8.2 多线程使用
c
#include <pthread.h>
void *worker_thread(void *arg) {
// 每个线程使用独立的连接
TAOS *taos = taos_connect("localhost", "root", "taosdata", "test", 0);
// 执行操作...
taos_close(taos);
return NULL;
}
int main() {
taos_init();
taos_options(TSDB_OPTION_DRIVER, "websocket");
pthread_t threads[10];
for (int i = 0; i < 10; i++) {
pthread_create(&threads[i], NULL, worker_thread, NULL);
}
for (int i = 0; i < 10; i++) {
pthread_join(threads[i], NULL);
}
taos_cleanup();
return 0;
}
注意 :TAOS 连接对象不是线程安全的,每个线程应使用独立的连接。
8.3 异步查询
c
void async_callback(void *param, TAOS_RES *res, int code) {
if (code == 0) {
printf("异步查询成功\n");
TAOS_ROW row;
while ((row = taos_fetch_row(res))) {
// 处理数据
}
} else {
printf("异步查询失败:%s\n", taos_errstr(res));
}
taos_free_result(res);
}
int main() {
taos_options(TSDB_OPTION_DRIVER, "websocket");
TAOS *taos = taos_connect("localhost", "root", "taosdata", "test", 0);
// 发起异步查询
taos_query_a(taos, "SELECT * FROM meters", async_callback, NULL);
// 主线程继续执行其他任务
sleep(1); // 等待异步操作完成
taos_close(taos);
return 0;
}
第九步:完整示例项目
创建一个完整的监控数据采集程序:
项目结构:
tdengine_monitor/
├── CMakeLists.txt
├── include/
│ └── monitor.h
├── src/
│ ├── main.c
│ ├── database.c
│ └── collector.c
└── README.md
monitor.h:
c
#ifndef MONITOR_H
#define MONITOR_H
#include "taos.h"
// 初始化数据库
int init_database(TAOS *taos);
// 采集数据
int collect_metrics(TAOS *taos);
// 查询统计
int query_statistics(TAOS *taos);
#endif
database.c:
c
#include "monitor.h"
#include <stdio.h>
int init_database(TAOS *taos) {
const char *sqls[] = {
"CREATE DATABASE IF NOT EXISTS monitor",
"USE monitor",
"CREATE STABLE IF NOT EXISTS metrics "
"(ts TIMESTAMP, cpu_usage FLOAT, mem_usage FLOAT, disk_io INT) "
"TAGS (hostname BINARY(64), region BINARY(32))"
};
for (int i = 0; i < 3; i++) {
TAOS_RES *res = taos_query(taos, sqls[i]);
if (taos_errno(res) != 0) {
fprintf(stderr, "执行失败:%s\n", taos_errstr(res));
taos_free_result(res);
return -1;
}
taos_free_result(res);
}
printf("数据库初始化成功\n");
return 0;
}
collector.c:
c
#include "monitor.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int collect_metrics(TAOS *taos) {
// 模拟采集数据
float cpu = (float)(rand() % 100);
float mem = (float)(rand() % 100);
int disk_io = rand() % 10000;
char sql[1024];
snprintf(sql, sizeof(sql),
"INSERT INTO server01 USING metrics TAGS('server01', 'beijing') "
"VALUES (NOW, %.2f, %.2f, %d)",
cpu, mem, disk_io);
TAOS_RES *res = taos_query(taos, sql);
int code = taos_errno(res);
taos_free_result(res);
if (code == 0) {
printf("数据采集成功:CPU=%.2f%%, MEM=%.2f%%, DiskIO=%d\n",
cpu, mem, disk_io);
return 0;
}
return -1;
}
int query_statistics(TAOS *taos) {
const char *sql =
"SELECT hostname, AVG(cpu_usage), AVG(mem_usage), MAX(disk_io) "
"FROM metrics "
"WHERE ts >= NOW - 1h "
"GROUP BY hostname";
TAOS_RES *res = taos_query(taos, sql);
if (taos_errno(res) != 0) {
fprintf(stderr, "查询失败:%s\n", taos_errstr(res));
taos_free_result(res);
return -1;
}
printf("\n=== 最近 1 小时统计 ===\n");
TAOS_ROW row;
while ((row = taos_fetch_row(res))) {
printf("主机:%s, 平均CPU:%.2f%%, 平均内存:%.2f%%, 最大磁盘IO:%d\n",
(char *)row[0],
*(double *)row[1],
*(double *)row[2],
*(int *)row[3]);
}
taos_free_result(res);
return 0;
}
main.c:
c
#include "monitor.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
// 初始化
taos_init();
taos_options(TSDB_OPTION_DRIVER, "websocket");
// 连接数据库
TAOS *taos = taos_connect("localhost", "root", "taosdata", NULL, 0);
if (taos == NULL) {
fprintf(stderr, "连接失败:%s\n", taos_errstr(NULL));
return -1;
}
printf("已连接到 TDengine\n");
// 初始化数据库
if (init_database(taos) != 0) {
taos_close(taos);
return -1;
}
// 持续采集数据(演示 10 次)
for (int i = 0; i < 10; i++) {
collect_metrics(taos);
sleep(1);
}
// 查询统计
query_statistics(taos);
// 清理
taos_close(taos);
taos_cleanup();
printf("程序结束\n");
return 0;
}
编译运行:
bash
mkdir build && cd build
cmake ..
make
./tdengine_monitor
总结
本指南涵盖了 TDengine C/C++ 连接器的核心概念和常用操作:
- 安装配置:安装客户端并验证环境
- 连接方式:WebSocket(推荐)和原生连接
- 基础操作:连接、查询、插入、关闭
- 高级特性:参数绑定、批量操作、数据订阅
- 最佳实践:错误处理、资源管理、性能优化
- 实战项目:完整的监控数据采集示例
获取帮助
- 官方文档:https://docs.taosdata.com/
- GitHub Issues:https://github.com/taosdata/TDengine/issues
- 社区论坛:https://github.com/taosdata/TDengine/discussions
- 企业支持:support@taosdata.com
关于 TDengine
TDengine 专为物联网IoT平台、工业大数据平台设计。其中,TDengine TSDB 是一款高性能、分布式的时序数据库(Time Series Database),同时它还带有内建的缓存、流式计算、数据订阅等系统功能;TDengine IDMP 是一款AI原生工业数据管理平台,它通过树状层次结构建立数据目录,对数据进行标准化、情景化,并通过 AI 提供实时分析、可视化、事件管理与报警等功能。