TDengine 与 taosAdapter 的结合(二)
五、开发实战步骤
(一)环境搭建
在开始 TDengine 与 taosAdapter 结合的 RESTful 接口开发之前,需要先完成相关环境的搭建,包括 TDengine 和 taosAdapter 的安装与配置,以及相关依赖的安装。
- TDengine 安装:
-
- Linux 系统:可以从 TDengine 官方网站(https://www.taosdata.com/cn/all-downloads/ )下载适合系统的安装包,目前支持 x86_64、ARM64 等多种架构 。下载完成后,解压安装包,进入解压目录,执行安装脚本./install.sh。在安装过程中,可能需要设置一些参数,如主机名、集群节点信息等,按照提示进行设置即可。安装完成后,可以通过systemctl start taosd命令启动 TDengine 服务,使用systemctl status taosd命令查看服务状态。
-
- Windows 系统:同样从官方网站下载 Windows 版本的安装包,双击安装程序,按照安装向导的提示完成安装。安装完成后,可以在开始菜单中找到 TDengine 的相关程序,或者在安装目录下找到taosd.exe文件,通过命令行启动服务,如taosd -c C:\TDengine\cfg(假设安装目录为 C:\TDengine)。
- taosAdapter 安装与配置:
-
- 安装:taosAdapter 通常随 TDengine 安装包一起提供,在安装 TDengine 时会自动安装。如果需要单独安装,可以从 TDengine 官方网站下载对应的 taosAdapter 安装包。在 Linux 系统上,安装完成后,taosAdapter 服务默认由 systemd 管理 。
-
- 配置:taosAdapter 的配置文件默认位于/etc/taos/taosadapter.toml(Linux)或C:\TDengine\cfg\taosadapter.toml(Windows)。打开配置文件,可以进行以下常见配置:
-
-
- 端口配置:默认情况下,taosAdapter 监听 6041 端口提供 RESTful 服务 。如果该端口已被占用,可以修改[http]部分的port参数,指定其他可用端口。
-
-
-
- 认证配置:可以配置用户名和密码进行身份认证。在[http]部分,设置user和password参数,确保安全性。
-
-
-
- 其他配置:根据实际需求,还可以配置日志级别、连接池大小等参数。例如,修改[log]部分的level参数来调整日志记录的详细程度,将level = "info"改为level = "debug"可以获取更详细的调试信息。
-
配置完成后,通过systemctl start taosadapter(Linux)或在 Windows 服务中启动 taosAdapter 服务,使用systemctl status taosadapter(Linux)或检查 Windows 服务状态来确认服务是否正常运行。
- 相关依赖安装:根据开发语言和框架的不同,可能需要安装一些相关依赖。如果使用 Python 进行开发,并且使用requests库来发送 HTTP 请求与 taosAdapter 进行交互,可以使用pip install requests命令安装requests库;如果使用 Java 开发,并且使用HttpClient来处理 HTTP 请求,需要在项目的pom.xml文件中添加HttpClient的依赖:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
以上步骤完成后,就搭建好了 TDengine 与 taosAdapter 结合开发 RESTful 接口的基础环境。
(二)接口开发流程
完成环境搭建后,就可以开始进行 RESTful 接口的开发了。以下是从需求分析、设计接口到编码实现的具体步骤:
- 需求分析:首先需要明确业务需求,确定需要通过 RESTful 接口对 TDengine 进行哪些数据操作。在一个物联网设备监控项目中,可能需要实现以下功能:
-
- 设备数据的实时写入,包括设备 ID、时间戳、各种传感器数据(如温度、湿度、压力等)。
-
- 根据设备 ID 和时间范围查询设备的历史数据。
-
- 获取所有设备的列表信息。
- 设计接口:根据需求分析的结果,按照 RESTful 架构风格设计接口。设计原则是将 TDengine 中的数据和操作抽象为资源,并使用 HTTP 方法进行访问。
-
- 数据写入接口:使用 POST 方法,将设备数据以 JSON 格式发送到/api/v1/databases/{database_name}/tables/{table_name}/data 。假设数据库名为iot_data,表名为device_sensor_data,则接口地址为/api/v1/databases/iot_data/tables/device_sensor_data/data。请求体示例如下:
[
{
"device_id": "device_001",
"ts": "2023-10-01T12:00:00Z",
"temperature": 25.5,
"humidity": 60.0,
"pressure": 1013.2
},
{
"device_id": "device_002",
"ts": "2023-10-01T12:00:00Z",
"temperature": 26.0,
"humidity": 58.0,
"pressure": 1012.8
}
]
- 数据查询接口:使用 GET 方法,通过在 URL 中添加参数来指定查询条件。查询设备device_001在 2023 年 10 月 1 日的所有数据,接口地址可以设计为/api/v1/databases/iot_data/tables/device_sensor_data/data?device_id=device_001&start_time=2023-10-01T00:00:00Z&end_time=2023-10-01T23:59:59Z 。
- 获取设备列表接口:使用 GET 方法,访问/api/v1/databases/{database_name}/devices 。对于上述物联网项目,接口地址为/api/v1/databases/iot_data/devices,返回所有设备的基本信息,如设备 ID、设备名称、设备类型等。
- 编码实现:根据设计好的接口,使用选定的开发语言和框架进行编码实现。如果使用 Python 和 Flask 框架来实现上述接口,可以参考以下代码示例:
from flask import Flask, request, jsonify
import requests
app = Flask(__name__)
# TDengine RESTful 接口地址前缀
TDENGINE_REST_URL = "http://localhost:6041/rest/sql"
TDENGINE_USER = "root"
TDENGINE_PASSWORD = "taosdata"
# 数据写入接口
@app.route('/api/v1/databases/<database_name>/tables/<table_name>/data', methods=['POST'])
def write_data(database_name, table_name):
data = request.json
sql_values = []
for item in data:
device_id = item['device_id']
ts = item['ts']
temperature = item['temperature']
humidity = item['humidity']
pressure = item['pressure']
sql_values.append(f"('{device_id}', '{ts}', {temperature}, {humidity}, {pressure})")
sql = f"INSERT INTO {database_name}.{table_name} (device_id, ts, temperature, humidity, pressure) VALUES {','.join(sql_values)}"
response = requests.post(TDENGINE_REST_URL, auth=(TDENGINE_USER, TDENGINE_PASSWORD), data=sql)
if response.status_code == 200:
return jsonify({"status": "success", "message": "Data inserted successfully"}), 200
else:
return jsonify({"status": "error", "message": "Failed to insert data"}), 500
# 数据查询接口
@app.route('/api/v1/databases/<database_name>/tables/<table_name>/data', methods=['GET'])
def query_data(database_name, table_name):
device_id = request.args.get('device_id')
start_time = request.args.get('start_time')
end_time = request.args.get('end_time')
sql_conditions = []
if device_id:
sql_conditions.append(f"device_id = '{device_id}'")
if start_time:
sql_conditions.append(f"ts >= '{start_time}'")
if end_time:
sql_conditions.append(f"ts <= '{end_time}'")
sql_condition_str = " AND ".join(sql_conditions)
sql = f"SELECT * FROM {database_name}.{table_name}"
if sql_condition_str:
sql += f" WHERE {sql_condition_str}"
response = requests.post(TDENGINE_REST_URL, auth=(TDENGINE_USER, TDENGINE_PASSWORD), data=sql)
if response.status_code == 200:
result = response.json()
return jsonify({"status": "success", "data": result['data']}), 200
else:
return jsonify({"status": "error", "message": "Failed to query data"}), 500
# 获取设备列表接口
@app.route('/api/v1/databases/<database_name>/devices', methods=['GET'])
def get_devices(database_name):
sql = f"SELECT DISTINCT device_id FROM {database_name}.device_sensor_data"
response = requests.post(TDENGINE_REST_URL, auth=(TDENGINE_USER, TDENGINE_PASSWORD), data=sql)
if response.status_code == 200:
result = response.json()
device_list = [item[0] for item in result['data']]
return jsonify({"status": "success", "devices": device_list}), 200
else:
return jsonify({"status": "error", "message": "Failed to get device list"}), 500
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5000)
以上代码通过 Flask 框架创建了一个简单的 Web 服务,实现了数据写入、查询和获取设备列表的 RESTful 接口。每个接口通过requests库向 taosAdapter 提供的 RESTful 接口发送 SQL 语句,实现对 TDengine 的操作,并返回相应的结果。
(三)代码示例与解释
下面给出使用 Python 和 Java 调用 RESTful 接口进行数据操作的实际代码示例,并对关键代码进行解释。
Python 代码示例:
import requests
# TDengine RESTful 接口地址前缀
TDENGINE_REST_URL = "http://localhost:6041/rest/sql"
TDENGINE_USER = "root"
TDENGINE_PASSWORD = "taosdata"
# 插入数据示例
def insert_data():
database_name = "test_db"
table_name = "test_table"
data = [
{
"col1": "value1",
"col2": 100,
"ts": "2023-10-05T10:00:00Z"
},
{
"col1": "value2",
"col2": 200,
"ts": "2023-10-05T10:01:00Z"
}
]
sql_values = []
for item in data:
col1 = item['col1']
col2 = item['col2']
ts = item['ts']
sql_values.append(f"('{col1}', {col2}, '{ts}')")
sql = f"INSERT INTO {database_name}.{table_name} (col1, col2, ts) VALUES {','.join(sql_values)}"
response = requests.post(TDENGINE_REST_URL, auth=(TDENGINE_USER, TDENGINE_PASSWORD), data=sql)
if response.status_code == 200:
print("Data inserted successfully")
else:
print("Failed to insert data")
# 查询数据示例
def query_data():
database_name = "test_db"
table_name = "test_table"
sql = f"SELECT * FROM {database_name}.{table_name}"
response = requests.post(TDENGINE_REST_URL, auth=(TDENGINE_USER, TDENGINE_PASSWORD), data=sql)
if response.status_code == 200:
result = response.json()
for row in result['data']:
print(row)
else:
print("Failed to query data")
if __name__ == "__main__":
insert_data()
query_data()
代码解释:
- TDENGINE_REST_URL:定义了 taosAdapter 提供的 RESTful 接口地址,这里假设 taosAdapter 运行在本地,端口为 6041。
- TDENGINE_USER和TDENGINE_PASSWORD:分别为 TDengine 的用户名和密码,用于身份认证。
- insert_data 函数:
-
- 构建要插入的数据列表,每个数据项包含col1、col2和ts字段。
-
- 通过循环构建 SQL 插入语句的 VALUES 部分,将数据转换为 SQL 可识别的格式。
-
- 使用requests.post方法向 TDengine 发送 POST 请求,请求的 URL 为TDENGINE_REST_URL,认证信息为(TDENGINE_USER, TDENGINE_PASSWORD),请求体为构建好的 SQL 语句。
-
- 根据响应状态码判断数据插入是否成功。
- query_data 函数:
-
- 构建简单的 SQL 查询语句,查询指定数据库和表中的所有数据。
-
- 同样使用requests.post方法发送请求,获取查询结果。
-
- 如果响应状态码为 200,解析响应的 JSON 数据,遍历并打印查询结果中的每一行数据。
Java 代码示例:
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class TDengineRestExample {
private static final String TDENGINE_REST_URL = "http://localhost:6041/rest/sql";
private static final String TDENGINE_USER = "root";
private static final String TDENGINE_PASSWORD = "taosdata";
// 插入数据示例
public static void insertData() {
String databaseName = "test_db";
String tableName = "test_table";
List<NameValuePair> data = new ArrayList<>();
data.add(new BasicNameValuePair("col1", "value1"));
data.add(new BasicNameValuePair("col2", "100"));
data.add(new BasicNameValuePair("ts", "2023-10-05T10:00:00Z"));
data.add(new BasicNameValuePair("col1", "value2"));
data.add(new BasicNameValuePair("col2", "200"));
data.add(new BasicNameValuePair("ts", "2023-10-05T10:01:00Z"));
StringBuilder sqlValues = new StringBuilder();
for (int i = 0; i < data.size(); i += 3) {
String col1 = data.get(i).getValue();
String col2 = data.get(i + 1).getValue();
String ts = data.get(i + 2).getValue();
if (sqlValues.length() > 0) {
sqlValues.append(",");
}
sqlValues.append("('").append(col1).append("',").append(col2).append(",'").append(ts).append("')");
}
String sql = "INSERT INTO " + databaseName + "." + tableName + " (col1, col2, ts) VALUES " + sqlValues;
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
HttpPost httpPost = new HttpPost(TDENGINE_REST_URL);
httpPost.setHeader("Authorization", "Basic " + org.apache.commons.codec.binary.Base64.encodeBase64String((TDENGINE_USER + ":" + TDENGINE_PASSWORD).getBytes()));
httpPost.setEntity(new UrlEncodedFormEntity(List.of(new BasicNameValuePair("sql", sql))));
HttpResponse response = httpClient.execute(httpPost);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200) {
System.out.println("Data inserted successfully");
} else {
System.out.println("Failed to insert data");
}
} catch (IOException e) {
e.printStackTrace();
}
}
// 查询数据示例
public static void queryData() {
String databaseName = "test_db";
String tableName = "test_table";
String sql = "SELECT * FROM " + databaseName + "." + tableName;
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
HttpPost httpPost = new HttpPost(TDENGINE_REST_URL);
httpPost.setHeader("Authorization", "Basic " + org.apache.commons.codec.binary.Base64.encodeBase64String((TDENGINE_USER + ":" + TDENGINE_PASSWORD).getBytes()));
httpPost.setEntity(new UrlEncodedFormEntity(List
## 六、常见问题与解决方案
在TDengine与taosAdapter结合进行RESTful接口开发过程中,可能会遇到一些常见问题,以下是对这些问题的分析及相应解决方案:
- **连接失败**:
- **问题描述**:客户端无法连接到taosAdapter提供的RESTful接口,返回连接超时或拒绝连接的错误信息。
- **原因分析**:可能是网络问题,如防火墙阻止了客户端与服务器之间的通信;也可能是taosAdapter服务未正常启动,或者配置的端口被其他程序占用;还可能是主机地址、端口号、用户名、密码等连接参数配置错误。
- **解决方案**:首先检查网络连接,确保客户端和服务器之间的网络畅通,可以通过ping命令测试网络连通性;检查防火墙设置,确保允许客户端访问taosAdapter服务所在的端口,在Linux系统上,可以使用`iptables -I INPUT -p tcp --dport 6041 -j ACCEPT`命令允许访问6041端口(假设taosAdapter使用该端口) ;确认taosAdapter服务已正常启动,使用`systemctl status taosadapter`命令查看服务状态,如果服务未启动,使用`systemctl start taosadapter`命令启动服务;仔细核对连接参数,确保主机地址、端口号、用户名、密码等配置正确无误。
- **数据传输错误**:
- **问题描述**:在进行数据写入或查询时,出现数据传输错误,如数据丢失、数据格式错误等。
- **原因分析**:数据丢失可能是由于网络不稳定,在数据传输过程中出现丢包现象;数据格式错误可能是因为客户端发送的数据格式不符合TDengine的要求,或者在数据解析过程中出现问题。
- **解决方案**:对于网络不稳定导致的数据丢失问题,可以增加重试机制。在代码中,使用循环和异常处理来实现数据传输失败后的重试操作。在Python中使用`requests`库进行数据写入时:
```python
import requests
import time
TDENGINE_REST_URL = "http://localhost:6041/rest/sql"
TDENGINE_USER = "root"
TDENGINE_PASSWORD = "taosdata"
data = [
{
"col1": "value1",
"col2": 100,
"ts": "2023-10-05T10:00:00Z"
}
]
sql_values = []
for item in data:
col1 = item['col1']
col2 = item['col2']
ts = item['ts']
sql_values.append(f"('{col1}', {col2}, '{ts}')")
sql = f"INSERT INTO test_db.test_table (col1, col2, ts) VALUES {','.join(sql_values)}"
max_retries = 3
retry_delay = 2
for retry in range(max_retries):
try:
response = requests.post(TDENGINE_REST_URL, auth=(TDENGINE_USER, TDENGINE_PASSWORD), data=sql)
if response.status_code == 200:
print("Data inserted successfully")
break
except Exception as e:
print(f"Failed to insert data, retry {retry + 1}: {e}")
time.sleep(retry_delay)
这段代码中,设置了最大重试次数为 3 次,每次重试间隔 2 秒。如果数据传输失败,会捕获异常并进行重试,直到成功插入数据或达到最大重试次数。对于数据格式错误问题,要仔细检查数据格式,确保符合 TDengine 的要求。在进行数据写入时,严格按照 TDengine 支持的数据类型和格式组织数据,在使用 JSON 格式传输数据时,确保 JSON 结构正确,字段名称和数据类型与 TDengine 表结构一致。在解析查询结果时,也要根据 TDengine 返回的数据格式进行正确的解析。
- taosAdapter 无响应:
-
- 问题描述:客户端发送请求后,taosAdapter 长时间无响应,服务端也没有返回任何错误信息。
-
- 原因分析:可能是 taosAdapter 负载过高,无法及时处理请求;也可能是请求处理过程中出现死锁或其他异常情况,导致 taosAdapter 服务挂起;还可能是某些频繁请求的操作(如健康检查语句)导致服务资源耗尽。
-
- 解决方案:监控 taosAdapter 的性能指标,如 CPU 使用率、内存占用、请求队列长度等,使用top、htop等工具查看系统资源使用情况 。如果发现 taosAdapter 负载过高,可以考虑优化系统配置,增加服务器资源,如内存、CPU 等;对 taosAdapter 进行性能调优,如调整连接池大小、优化 SQL 语句等。在 taosadapter.toml 配置文件中,可以适当增加[http]部分的max_connections参数值,以提高并发处理能力 。如果是请求处理过程中出现死锁或异常情况,可以通过查看 taosAdapter 的日志文件(默认位于/var/log/taos/taosadapter.log )来排查问题。根据日志信息定位异常原因,如 SQL 语句错误、数据库连接问题等,进行相应的修复。对于由于频繁请求某些操作导致的问题,要优化请求策略。在黑格智能 3D 打印业务从 2.x 升级到 3.x 过程中,微服务通过 restful 方式连接 TDengine 时,taosAdapter 出现无响应但 taosd 服务正常的现象,经排查是大量使用 “show cluster alive” 作为微服务监听语句的频繁请求导致。后续将健康检查语句更换为 “select 1”,顺利解决了这个问题 。
七、总结与展望
通过本文的介绍和实践,我们深入了解了 TDengine 与 taosAdapter 结合在 RESTful 接口开发中的应用。TDengine 作为一款高性能的时序数据库,具备强大的时序数据处理能力,而 taosAdapter 则为 TDengine 提供了便捷的 RESTful 接口支持,使得 TDengine 能够更轻松地与各种应用程序集成。
在实际应用中,TDengine 与 taosAdapter 的结合展现出了诸多优势,便捷的跨平台访问能力,让不同操作系统和编程语言的应用都能与 TDengine 进行交互;简化了系统集成过程,降低了与现有系统集成的难度和成本;灵活的数据交互方式,满足了多样化的应用场景需求。通过开发实战步骤,我们学习了如何搭建环境、设计接口并进行编码实现,掌握了使用 Python 和 Java 调用 RESTful 接口进行数据操作的方法。同时,我们也了解了在开发过程中可能遇到的常见问题及解决方案,为实际项目的开发提供了保障。
展望未来,随着物联网、工业互联网等领域的不断发展,时序数据的处理需求将持续增长。TDengine 和 taosAdapter 也将不断演进和完善。在功能方面,可能会进一步优化 RESTful 接口的性能和稳定性,增加更多对复杂查询和数据分析的支持,以满足企业日益增长的业务需求;在兼容性方面,有望支持更多的协议和标准,与更多的第三方工具和系统实现无缝对接,进一步拓展其应用场景;在生态建设方面,社区可能会更加活跃,吸引更多的开发者参与,共同推动 TDengine 和 taosAdapter 的发展,为时序数据处理领域提供更强大、更完善的解决方案。作为开发者,我们应持续关注 TDengine 和 taosAdapter 的发展动态,不断探索其在不同场景下的应用,充分发挥其优势,为项目的成功实施提供有力支持 。
相关文章:
TDengine 与 taosAdapter 的结合(二)
五、开发实战步骤 (一)环境搭建 在开始 TDengine 与 taosAdapter 结合的 RESTful 接口开发之前,需要先完成相关环境的搭建,包括 TDengine 和 taosAdapter 的安装与配置,以及相关依赖的安装。 TDengine 安装…...
OBS 中如何设置固定码率(CBR)与可变码率(VBR)?
在使用 OBS 进行录制或推流时,设置“码率控制模式”(Rate Control)是非常重要的一步。常见的控制模式包括: CBR(固定码率):保持恒定的输出码率,适合直播场景。 VBR(可变码率):在允许的范围内动态调整码率,适合本地录制、追求画质。 一、CBR vs. VBR 的差异 项目CBR…...
优艾智合人形机器人“巡霄”,开启具身多模态新时代
近日,优艾智合-西安交大具身智能机器人研究院公布人形机器人矩阵,其中轮式人形机器人“巡霄”首次亮相。 “巡霄”集成移动导航、操作控制与智能交互技术,具备跨场景泛化能,适用于家庭日常服务、电力设备巡检、半导体精密操作及仓…...
蓝桥杯小白打卡第七天(第十四届真题)
小蓝的金属冶炼转换率问题 小蓝有一个神奇的炉子用于将普通金属 (O) 冶炼成为一种特殊金属 (X) 。 这个炉子有一个称作转换率的属性 (V) ,(V) 是一个正整数,这意味着消耗 (V) 个普通金属 (O) 恰好可以冶炼出一个特殊金属 (X) ,当普通金属 (…...
excel经验
Q:我现在有一个excel,有一列数据,大概两千多行。如何在这一列中 筛选出具有关键字的内容,并输出到另外一列中。 A: 假设数据在A列(A1开始),关键字为“ABC”在相邻空白列(如B1)输入公…...
【Pandas】pandas DataFrame astype
Pandas2.2 DataFrame Conversion 方法描述DataFrame.astype(dtype[, copy, errors])用于将 DataFrame 中的数据转换为指定的数据类型 pandas.DataFrame.astype pandas.DataFrame.astype 是一个方法,用于将 DataFrame 中的数据转换为指定的数据类型。这个方法非常…...
【Netty4核心原理④】【简单实现 Tomcat 和 RPC框架功能】
文章目录 一、前言二、 基于 Netty 实现 Tomcat1. 基于传统 IO 重构 Tomcat1.1 创建 MyRequest 和 MyReponse 对象1.2 构建一个基础的 Servlet1.3 创建用户业务代码1.4 完成web.properties 配置1.5 创建 Tomcat 启动类 2. 基于 Netty 重构 Tomcat2.1 创建 NettyRequest和 Netty…...
4.6学习总结
包装类 包装类:基本数据类型对应的引用数据类型 JDK5以后新增了自动装箱,自动拆箱 以后获取包装类方法,不需要new,直接调用方法,直接赋值即可 //1.把整数转成二进制,十六进制 String str1 Integer.toBin…...
MySQL学习笔记五
第七章数据过滤 7.1组合WHERE子句 7.1.1AND操作符 输入: SELECT first_name, last_name, salary FROM employees WHERE salary < 4800 AND department_id 60; 输出: 说明:MySQL允许使用多个WHERE子句,可以以AND子句或OR…...
成为社交场的导演而非演员
一、情绪的本质:社交信号而非自我牢笼 进化功能:情绪是人类进化出的原始社交工具。愤怒触发群体保护机制,悲伤唤起同情支持,喜悦巩固联盟关系。它们如同可见光谱,快速传递生存需求信号。双刃剑效应:情绪的…...
怎么使用vue3实现一个优雅的不定高虚拟列表
前言 很多同学将虚拟列表当做亮点写在简历上面,但是却不知道如何手写,那么这个就不是加分项而是减分项了。实际项目中更多的是不定高虚拟列表,这篇文章来教你不定高如何实现。 什么是不定高虚拟列表 不定高的意思很简单,就是不…...
LemonSqueezy: 1靶场渗透
LemonSqueezy: 1 来自 <LemonSqueezy: 1 ~ VulnHub> 1,将两台虚拟机网络连接都改为NAT模式 2,攻击机上做namp局域网扫描发现靶机 nmap -sn 192.168.23.0/24 那么攻击机IP为192.168.23.182,靶场IP192.168.23.225 3,对靶机进…...
2025 年山东保安员职业资格考试要点梳理
山东作为人口大省,保安市场规模庞大。2025 年考试报考条件常规。报名通过山东省各市公安机关指定的培训机构或政务服务窗口,提交资料与其他地区类似。 理论考试注重对山东地域文化特色相关安保知识的考查,如在孔庙等文化圣地安保中&#x…...
ARM处理器内核全解析:从Cortex到Neoverse的架构与区别
ARM处理器内核全解析:从Cortex到Neoverse的架构与区别 ARM作为全球领先的处理器架构设计公司,其内核产品线覆盖了从高性能计算到低功耗嵌入式应用的广泛领域。本文将全面解析ARM处理器的内核分类、架构特点、性能差异以及应用场景,帮助读者深…...
网络缓冲区
网络缓冲区分为内核缓冲区和用户态网络缓冲区 我们重点要实现用户态网络缓冲区 1.设计用户态网络缓冲区的原因 ①.生产者和消费者的速度不匹配问题, 需要缓存数据。 ②.粘包处理问题, 不能确保一次系统调用读取或写入完整数据包。 2.代码实现(cha…...
数据仓库的核心架构与关键技术(数据仓库系列二)
目录 一、引言 二、数据仓库的核心架构 三、数据仓库的关键技术 1 数据集成与治理 2 查询优化与性能提升 3 数据共享服务 BI:以Tableau为例 SQL2API:以麦聪QuickAPI为例 4 实时数据处理 四、技术的协同作用 五、总结与展望 六、预告 一、引言…...
基于PyQt5与OpenCV的图像处理系统设计与实现
1. 系统概述 本系统是一个集成了多种经典图像处理算法的图形用户界面(GUI)应用程序,采用Python语言开发,基于PyQt5框架构建用户界面,利用OpenCV库实现核心图像处理功能。 系统支持11种图像处理操作,每种操作都提供参数实时调节功能,并具备原始图像与处理后图像的双视图对…...
如何根据设计稿进行移动端适配:全面详解
如何根据设计稿进行移动端适配:全面详解 文章目录 如何根据设计稿进行移动端适配:全面详解1. **理解设计稿**1.1 设计稿的尺寸1.2 设计稿的单位 2. **移动端适配的核心技术**2.1 使用 viewport 元标签2.1.1 代码示例2.1.2 参数说明 2.2 使用相对单位2.2.…...
什么是大型语言模型(LLM)?哪个大模型更好用?
什么是 LLM? ChatGPT 是一种大型语言模型 (LLM),您可能对此并不陌生。它以非凡的能力而闻名,已证明能够出色地完成各种任务,例如通过考试、生成产品内容、解决问题,甚至在最少的输入提示下编写程序。 他们的实力现已…...
集合学习内容总结
集合简介 1、Scala 的集合有三大类:序列 Seq、集Set、映射 Map,所有的集合都扩展自 Iterable 特质。 2、对于几乎所有的集合类,Scala 都同时提供了可变和不可变的版本,分别位于以下两个包 不可变集合:scala.collect…...
使用typedef和不使用的区别
使用 typedef 定义的函数指针类型 typedef sensor_drv_params_t* (*load_sensor_drv_func)(); 不使用 typedef 的函数指针声明 sensor_drv_params_t* (*load_sensor_drv_func)(); 这两者看似相似,但在语义和用途上有显著区别。下面将详细解释这两种声明的区别、各…...
基于线性回归模型的汽车燃油效率预测
基于线性回归模型的汽车燃油效率预测 1.作者介绍2.线性回归介绍2.1 线性回归简介2.2 线性回归应用场景 3.基于线性回归模型的汽车燃油效率预测实验3.1 Auto MPG Data Set数据集3.2代码调试3.3完整代码3.4结果展示 4.问题分析 基于线性回归模型的汽车燃油效率预测 1.作者介绍 郝…...
Playwright之自定义浏览器目录访问出错:BrowserType.launch: Executable doesn‘t exist
Playwright之自定义浏览器目录访问出错:BrowserType.launch: Executable doesn’t exist 问题描述: 在使用playwright进行浏览器自动化的时候,配置了自定义的浏览器目录,当按照自定义的浏览器目录启动浏览器进行操作时,…...
如何拿到iframe中嵌入的游戏数据
在 iframe 中嵌入的游戏数据是否能被获取,取决于以下几个关键因素: 1. 同源策略 浏览器的同源策略是核心限制。如果父页面和 iframe 中的内容同源(即协议、域名和端口号完全相同),那么可以直接通过 JavaScript 访问 …...
优选算法第七讲:分治
优选算法第七讲:分治 1.分治_快排1.1颜色分类1.2排序数组1.3数组中第k个最大元素1.4库存管理II 2.分治_归并2.1排序数组2.2交易逆序对的总数2.3计算右侧小于当前元素的个数2.4翻转对 1.分治_快排 1.1颜色分类 1.2排序数组 1.3数组中第k个最大元素 1.4库存管理II 2.…...
OpenBMC:BmcWeb 处理http请求4 处理路由对象
OpenBMC:BmcWeb 处理http请求2 查找路由对象-CSDN博客 Router::handle通过findRoute获取了FindRouteResponse对象foundRoute void handle(const std::shared_ptr<Request>& req,const std::shared_ptr<bmcweb::AsyncResp>& asyncResp){FindRouteResponse …...
直流电能表计量解决方案适用于光伏储能充电桩基站等场景
多场景解决方案,准确测量 01 市场规模与增长动力 全球直流表市场预测: 2025年市场规模14亿美元,CAGR超15%。 驱动因素:充电桩、光伏/储能、基站、直流配电 市场增长引擎分析: 充电桩随新能源车迅猛增长ÿ…...
x-cmd install | Slumber - 告别繁琐,拥抱高效的终端 HTTP 客户端
目录 核心优势,一览无遗安装应用场景,无限可能示例告别 GUI,拥抱终端 还在为调试 API 接口,发送 HTTP 请求而苦恼吗?还在各种 GUI 工具之间切换,只为了发送一个简单的请求吗?现在,有…...
git修改已经push的commit的message
1.修改信息 2.修改message 3.强推...
STM32 基础2
STM32中断响应过程 1、中断源发出中断请求。 2、判断处理器是否允许中断,以及该中断源是否被屏蔽。 3、中断优先级排队。 4、处理器暂停当前程序,保护断点地址和处理器的当前状态,根据中断类型号,查找中断向量表,转到…...
【STL 之速通pair vector list stack queue set map 】
考list 的比较少 --双端的啦 pair 想下,程序是什么样的. 我是我们要带着自己的思考去学习DevangLic.. #include <iostream> #include <utility> #include <string>using namespace std;int main() {// 第一部分:创建并输出两个 pair …...
深度学习篇---LSTM+Attention模型
文章目录 前言1. LSTM深入原理剖析1.1 LSTM 架构的进化理解遗忘门简介数学表达式实际作用 输入门简介数学表达式后选候选值实际作用 输出门简介数学表达式最终输出实际作用 1.2 Attention 机制的动态特性内容感知位置无关可解释性数学本质 1.3 LSTM与Attention的协同效应组合优…...
React 多个 HOC 嵌套太深,会带来哪些隐患?
在 React 中,使用多个 高阶组件(HOC,Higher-Order Component) 可能会导致组件层级变深,这可能会带来以下几个影响: 一、带来的影响 1、调试困难 由于组件被多个 HOC 包裹,React 开发者工具&am…...
企业工厂生产线马达保护装置 功能参数介绍
安科瑞刘鸿鹏 摘要 工业生产中,电压暂降(晃电)是导致电动机停机、生产中断的主要原因之一,给企业带来巨大的经济损失。本文以安科瑞晃电再起动控制器为例,探讨抗晃电保护器在生产型企业工厂中的应用,分析…...
Redis 的五种数据类型面试回答
这里简单介绍一下面试回答、我之前有详细的去学习、但是一直都觉得太多内容了、太深入了 然后面试的时候不知道从哪里讲起、于是我写了这篇CSDN帮助大家面试回答、具体的深入解析下次再说 面试官你好 我来介绍一下Redis的五种基本数据类型 有String List Set ZSet Map 五种基…...
多线程代码案例(定时器) - 3
定时器,是我们日常开发所常用的组件工具,类似于闹钟,设定一个时间,当时间到了之后,定时器可以自动的去执行某个逻辑 目录 Timer 的基本使用 实现一个 Timer 通过这个类,来描述一个任务 通过这个类&…...
基于大模型的GCSE预测与治疗优化系统技术方案
目录 技术方案文档:基于大模型的GCSE预测与治疗优化系统1. 数据预处理模块功能:整合多模态数据(EEG、MRI、临床指标等),标准化并生成训练集。伪代码流程图2. 大模型架构(Transformer-GNN混合模型)功能:联合建模时序信号(EEG)与空间结构(脑网络)。伪代码流程图3. 术…...
IntelliJ IDEA 中 Continue 插件使用 DeepSeek-R1 模型指南
IntelliJ IDEA 中 Continue 插件使用 DeepSeek-R1 模型指南 Continue 是一款开源的 AI 编码助手插件,支持 IntelliJ IDEA 等 JetBrains 系列 IDE。它可以通过连接多种语言模型(如 DeepSeek-R1)提供实时代码生成、问题解答和单元测试生成等功…...
Valgrind——内存调试和性能分析工具
文章目录 一、Valgrind 介绍二、Valgrind 功能和使用1. 主要功能2. 基本用法2.1 常用选项2.2 内存泄漏检测2.3 详细报告2.4 性能分析2.5 多线程错误检测 三、在 Ubuntu 上安装 Valgrind四、示例1. 检测内存泄漏2. 使用未初始化的内存3. 内存读写越界4. 综合错误 五、工具集1. M…...
京东API智能风控引擎:基于行为分析识别恶意爬虫与异常调用
京东 API 智能风控引擎基于行为分析识别恶意爬虫与异常调用,主要通过以下几种方式实现: 行为特征分析 请求频率:正常用户对 API 的调用频率相对稳定,受到网络延迟、操作速度等因素限制。若发现某个 IP 地址或用户在短时间内对同一…...
Swift 解 LeetCode 250:搞懂同值子树,用递归写出权限系统检查器
文章目录 前言问题描述简单说:痛点分析:到底难在哪?1. 子树的概念搞不清楚2. 要不要“递归”?递归从哪开始?3. 怎么“边遍历边判断”?这套路不熟 后序遍历 全局计数器遍历过程解释一下:和实际场…...
Nginx搭建API网关服务教程-系统架构优化 API统一管理
超实用!用Nginx搭建API网关服务,让你的系统架构更稳更强大!🚀 亲们,今天来给大家种草一个超级实用的API网关搭建方案啦!👀 在如今的Web系统架构中,一个稳定、高性能、可扩展的API网…...
SQL2API是什么?SQL2API与BI为何对数据仓库至关重要?
目录 一、SQL2API是什么? 二、SQL2API的历史演变:从数据共享到服务化革命 1990年代:萌芽于数据仓库的数据共享需求 2010年代初:数据中台推动服务化浪潮 2022年左右:DaaS平台的兴起 2025年代:麦聪定义…...
CentOS 7无法上网问题解决
CentOS 7无法上网问题解决 问题 配置了桥接模式以后,能够ping通本地IP但是无法ping通www.baidu.com 这里的前提是VWare上已经对虚拟机桥接模式网卡做了正确的选择,比如我现在选择的就是当前能够上外网的网卡: 问题根因 DNS未正确配置。…...
优化 Web 性能:使用 WebP 图片(Uses WebP Images)
在 Web 开发中,图片资源的优化是提升页面加载速度和用户体验的关键。Google 的 Lighthouse 工具在性能审计中特别推荐“使用 WebP 图片”(Uses WebP Images),因为 WebP 格式在保持视觉质量的同时显著减少文件大小。本文将基于 Chr…...
SQL121 创建索引
-- 普通索引 CREATE INDEX idx_duration ON examination_info(duration);-- 唯一索引 CREATE UNIQUE INDEX uniq_idx_exam_id ON examination_info(exam_id);-- 全文索引 CREATE FULLTEXT INDEX full_idx_tag ON examination_info(tag);描述 现有一张试卷信息表examination_in…...
Leetcode - 周赛443
目录 一、3502. 到达每个位置的最小费用二、3503. 子字符串连接后的最长回文串 I三、3504. 子字符串连接后的最长回文串 II四、3505. 使 K 个子数组内元素相等的最少操作数 一、3502. 到达每个位置的最小费用 题目链接 本题是一道脑筋急转弯,实际就是计算前缀最小…...
dolphinscheduler单机部署链接oracle
部署成功请给小编一个赞或者收藏激励小编 1、安装准备 JDK版本:1.8或者1.8oracle版本:19Coracle驱动版本:8 2、安装jdk 下载地址:https://www.oracle.com/java/technologies/downloads/#java8 下载后上传到/tmp目录下。 然后执行下面命…...
Three.js 系列专题 5:加载外部模型
内容概述 Three.js 支持加载多种 3D 文件格式(如 GLTF、OBJ、FBX),这让开发者可以直接使用专业建模软件(如 Blender、Maya)创建的复杂模型。本专题将重点介绍 GLTF 格式的加载,并调整模型的位置和材质。 学习目标 理解常见 3D 文件格式及其特点。掌握使用 GLTFLoader 加…...
【C++算法】50.分治_归并_翻转对
文章目录 题目链接:题目描述:解法C 算法代码:图解 题目链接: 493. 翻转对 题目描述: 解法 分治 策略一:计算当前元素cur1后面,有多少元素的两倍比我cur1小(降序) 利用单…...