目录
1、Dashboard
1.1 查看和配置Dashboard
1.2 Dashboard界面
1.2.1 ADMIN
1.2.2 MONITORING
1.2.3 RULE ENGINE
1.2.4 MANAGEMENT
1.2.5 TOOLS
2、认证
2.1 简介
2.1.1 认证方式
2.1.2 EMQX身份认证流程
2.2 Username 认证
2.2.1 预设认证数据
2.2.2 HTTP API 管理认证数据
2.2.3 MQTTX客户端验证
2.3 Client ID 认证
2.3.1 预设认证数据
2.3.2 HTTP API 管理认证数据
2.3.3 MQTTX客户端验证
2.4 HTTP认证
2.4.1 认证原理
2.4.2 HTTP 请求信息
2.4.3 认证请求
2.4.4 认证服务开发
2.4.5 MQTTX客户端验证
3、客户端SDK
3.1 Eclipse Paho Java
3.1.1 Paho介绍
3.1.2 Paho实现消息收发
3.2 MQTT.js
3.2.1 API列表
3.2.2 MQTT.js实现消息收发
4. 日志与追踪
4.1 控制日志输出
4.2 日志级别
4.3 日志文件和日志滚动
4.4 针对日志级别输出日志文件
4.5 日志格式
4.6 日志级别和log handlers
4.7 运行时修改日志级别
4.8 日志追踪
1、Dashboard
EMQX 提供了 Dashboard 以方便用户管理设备与监控相关指标。通过 Dashboard可以查看服务器基本信息、负载情况和统计数据,可以查看某个客户端的连接状态等信息甚至断开其连接,也可以动态加载和卸载指定插件。除此之外,EMQ X Dashboard 还提供了规则引擎的可视化操作界面,同时集成了一个简易的 MQTT 客户端工具供用户测试使用。
EMQX Dashboard 功能由 emqx-dashboard 插件实现,该插件默认处于启用状态,它将在 EMQX 启动时自 动加载。如果你希望禁用 Dashboard 功能,你可以将 data/loaded_plugins 中的 {emqx_dashboard, true } 修改为 {emqx_dashboard, false } 。
1.1 查看和配置Dashboard
EMQ X Dashboard 是一个 Web 应用程序,你可以直接通过浏览器来访问它,无需安装任何其他软件。 当 EMQX 成功运行在你的本地计算机上且 EMQX Dashboard 被默认启用时,通过访问 http://localhost:18083 来查看Dashboard,默认用户名是 admin ,密码是 public 。
如果EMQX是基于docker容器部署的,可以在容器中的 etc/plugins/emqx_dashboard.conf 中查看或修改 EMQ X Dashboard 的配置。 EMQ X Dashboard 配置项可以分为默认用户 与监听器 两个部分:
默认用户
EMQ X Dashboard 可以配置多个用户,但在配置文件中仅支持配置默认用户。 需要注意的是,一旦您通过 Dashboard 修改了默认用户的密码,则默认用户的相关信息将以您在 Dashboard 上的最新改动为准,配置文件中的默认用户配置将被忽略。
监听器
EMQ X Dashboard 支持 HTTP 和 HTTPS 两种 Listener,但默认只启用了监听端口为 18083 的 HTTP Listener。
1.2 Dashboard界面
为了使用户在操作和浏览中可以快速地定位和切换当前位置,EMQ X Dashboard 采用了侧边导航的模式,默 认情况下 Dashboard 包含以下一级导航项目:
最新版本EMQ X Broker的Dashboard界面布局略有不同,增加了些导航,但基本都差不多
1.2.1 ADMIN
Users
您可以在 Users 页面查看和管理能够访问和操作 Dashboard 的用户:
Settings
目前 EMQ X Dashboard 仅支持修改主题和语言两种设置:
1.2.2 MONITORING
EMQ X Dashboard 提供了非常丰富的数据监控项目,完整地覆盖了服务端与客户端,这些信息都将在MONITORING 下的页面中被合理地展示给用户。
Overview
Overview 作为 Dashboard 的默认展示页面,提供了 EMQ X 当前节点的详细信息和集群其他节点的关键信息,以帮助用户快速掌握每个节点的状态。
Clients
Clients 页面提供了连接到指定节点的客户端列表,同时支持通过 Client ID 直接搜索客户端。除了查看客户端的基本信息,您还可以点击每条记录右侧的 Kick Out 按钮踢掉该客户端,注意此操作将断开客户端连接并终结其会话。
Clients 页面使用快照的方式来展示客户端列表,因此当客户端状态发生变化时页面并不会自动刷新,需要您手动刷新浏览器来获取最新客户端数据。
如果你无法在客户端列表获取到你需要的信息,你可以单击 Client ID 来查看客户端的详细信息。
我们将客户端详情中的各个字段分为了 连接 ,会话 和 指标 三类,以下为各字段的说明:
连接
会话
指标
在客户端详情的 Subscriptions 标签页中,您可以查看当前客户端的订阅信息,以及新建或取消订阅:
Topics
展示系统所有的Topic情况
Subscriptions
Subscriptions 页面提供了指定节点下的所有订阅信息,并且支持用户通过 Client ID 查询指定客户端的所有订阅。
1.2.3 RULE ENGINE
用 EMQ X 的规则引擎可以灵活地处理消息和事件,例如将消息转换成指定格式后存入数据库表或者重新发送到消息队列等等。为了方便用户更好地使用规则引擎,EMQ X Dashboard 提供了相应的可视化操作页面,您可以 点击 RULE ENGINE 导航项目来访问这些页面。
鉴于规则引擎的相关概念比较复杂, 涉及到的操作可能会占据相当大的篇幅,后面会单独写一篇博客来介绍。
1.2.4 MANAGEMENT
目前 EMQ X Dashboard 的 MANAGEMENT 导航项目下主要包括扩展插件 的监控管理页面和用于 HTTP API 认证的 AppID 与 AppSerect 的管理页面。
Plugins
Plugins 页面列举了 EMQ X 能够发现的所有插件,包括 EMQ X 官方插件与您遵循 EMQ X 官方标准自行开发的插件,您可以在此页面查看插件当前的运行状态以及随时启停插件。
可以看到,除了emqx-dashboard以外, EMQ X 还将默认启动 emqx-rule-engine等4个插件。
Applications
Applications 页面列举了当前已创建的应用,您可以在此页面进行诸如创建应用、临时禁用或启动某个应用的访问权限等操作。EMQ X 会创建一个 AppID 为 admin ,AppSecret 为 publish 的默认应用方便用户首次访问:
您可以点击 Application 页面右上角的 New App 按钮来创建一个新的应用,其中 AppID 与 AppSecret 是必 选项。创建完成后您可以点击 View 按钮来查看应用详情,AppSecret 也会在详情中显示。以下是相关字段的说明:
目前 EMQ X Dashboard 的 TOOLS 导航项目下主要包括 WebSocket 客户端工具页面以及 HTTP API 速查页面。
Websocket
Websocket 页面为您提供了一个简易但有效的 WebSocket 客户端工具,它包含了连接、订阅和发布功能,同时还能查看自己发送和接收的报文数据,我们期望它可以帮助您快速地完成某些场景或功能的测试验证:
HTTP API
HTTP API 页面列举了 EMQ X 目前支持的所有 HTTP API 及其说明:
2、认证
2.1 简介
身份认证是大多数应用的重要组成部分,MQTT 协议支持用户名密码认证,启用身份认证能有效阻止非法客户端的连接。
EMQ X 中的认证指的是当一个客户端连接到 EMQ X 的时候,通过服务器端的配置来控制客户端连接服务器的权限。
EMQ X 的认证支持包括两个层面:
MQTT 协议本身在 CONNECT 报文中指定用户名和密码,EMQ X 以插件形式支持基于 Username、 ClientID、HTTP、JWT、LDAP 及各类数据库如 MongoDB、MySQL、PostgreSQL、Redis 等多种形式的认证。
在传输层上,TLS 可以保证使用客户端证书的客户端到服务器的身份验证,并确保服务器向客户端验证服务器证书。也支持基于 PSK 的 TLS/DTLS 认证。
2.1.1 认证方式
EMQ X 支持使用内置数据源 (文件、内置数据库)、JWT 、外部主流数据库 和自定义 HTTP API 作为身份认证数据源。
连接数据源、进行认证逻辑通过插件实现的,每个插件对应一种认证方式,使用前需要启用相应的插件。
客户端连接时插件通过检查其 username/clientid 和 password 是否与指定数据源的信息一致来实现对客户端的身份认证。
EMQ X 支持的认证方式:
内置数据源
Username 认证
Cliend ID 认证
使用配置文件与 EMQ X 内置数据库提供认证数据源,通过 HTTP API 进行管理,足够简单轻量。
外部数据库
LDAP 认证
MySQL 认证
PostgreSQL 认证
Redis 认证
MongoDB 认证
外部数据库可以存储大量数据,同时方便与外部设备管理系统集成。
其他
HTTP 认证
JWT 认证
JWT 认证可以批量签发认证信息,HTTP 认证能够实现复杂的认证鉴权逻辑。
更改插件配置后需要重启插件才能生效,部分认证鉴权插件包含 ACL 功能
认证结果
任何一种认证方式最终都会返回一个结果:
认证成功:经过比对客户端认证成功
认证失败:经过比对客户端认证失败,数据源中密码与当前密码不一致忽略认证(ignore):当前认证方式中未查找到认证数据,无法显式判断结果是成功还是失败,交由认证链下一认证方式或匿名认证 来判断
匿名认证
EMQ X 默认配置中启用了匿名认证,任何客户端都能接入 EMQ X。没有启用认证插件或认证插件没有显式允许/拒绝(ignore)连接请求时,EMQ X 将根据匿名认证启用情况决定是否允许客户端连接。
配置匿名认证开关:
# 进入 etc/emqx.conf
## Value: true | false
allow_anonymous = true
生产环境中请禁用匿名认证。
注意:我们需要进入到容器内部修改该配置,然后重启EMQ X服务
密码加盐规则与哈希方法
EMQ X 多数认证插件中可以启用哈希方法,数据源中仅保存密码密文,保证数据安全。
启用哈希方法时,用户可以为每个客户端都指定一个 salt(盐)并配置加盐规则,数据库中存储的密码是按照。加盐规则与哈希方法处理后的密文。
以 MySQL 认证为例:
加盐规则与哈希方法配置:
# 进入etc/plugins/emqx_auth_mysql.conf
## 不加盐,仅做哈希处理
auth.mysql.password_hash = sha256
## salt 前缀:使用 sha256 加密 salt + 密码 拼接的字符串 auth.mysql.password_hash = salt,sha256
## salt 后缀:使用 sha256 加密 密码 + salt 拼接的字符串 auth.mysql.password_hash = sha256,salt
## pbkdf2 with macfun iterations dklen
## macfun: md4, md5, ripemd160, sha, sha224, sha256, sha384, sha512
## auth.mysql.password_hash = pbkdf2,sha256,1000,20
如何生成认证信息
为每个客户端分用户名、Client ID、密码以及 salt(盐)等信息
使用与 MySQL 认证相同加盐规则与哈希方法处理客户端信息得到密文
将客户端信息写入数据库,客户端的密码应当为密文信息
2.1.2 EMQX身份认证流程
根据配置的认证 SQL 结合客户端传入的信息,查询出密码(密文)和 salt(盐)等认证数据,没有查询结果时,认证将终止并返回 ignore 结果 。
根据配置的加盐规则与哈希方法计算得到密文,没有启用哈希方法则跳过此步 。
将数据库中存储的密文与当前客户端计算的到的密文进行比对,比对成功则认证通过,否则认证失败 。
写入数据的加盐规则、哈希方法与对应插件的配置一致时认证才能正常进行。更改哈希方法会造成现有认证数据失效。
认证链
当同时启用多个认证方式时,EMQ X 将按照插件开启先后顺序进行链式认证:
同时只启用一个认证插件可以提高客户端身份认证效率。
2.2 Username 认证
Username 认证使用配置文件预设客户端用户名与密码,支持通过 HTTP API 管理认证数据。
Username 认证不依赖外部数据源,使用上足够简单轻量。使用这种认证方式前需要开启插件,我们可以在Dashboard 里找到这个插件并开启。
插件:
emqx_auth_username
哈希方法
Username 认证默认使用 sha256 进行密码哈希加密,可在 etc/plugins/emqx_auth_username.conf 中更改:
配置哈希方法后,新增的预设认证数据与通过 HTTP API 添加的认证数据将以哈希密文存储在 EMQ X 内置数据库中。
2.2.1 预设认证数据
可以通过配置文件预设认证数据,编辑配置文件:etc/plugins/emqx_auth_username.conf
插件启动时将读取预设认证数据并加载到 EMQ X 内置数据库中,节点上的认证数据会在此阶段同步至集群中。
预设认证数据在配置文件中使用了明文密码,出于安全性与可维护性考虑应当避免使用该功能 。
2.2.2 HTTP API 管理认证数据
EMQ X提供了对应的HTTP API用以维护内置数据源中的认证信息,我们可以添加/查看/取消/更改认证数据 。
我们通过VSCode 来访问EMQ X的API /auth_username 完成认证数据的相关操作
打开VSCode下载插件
接下来我们就可以区VSCode去编写代码。
创建一个html文件
1、查看已有认证用户数据: GET api/v4/auth_username
@hostname = 192.168.200.129
@port=18083
@contentType=application/json
@userName=admin
@password=public
#############查看已有用户认证数据##############
GET http://{{hostname}}:{{port}}/api/v4/auth_username HTTP/1.1 Content-Type: {{contentType}}
Authorization: Basic {{userName}}:{{password}}
返回
2、添加认证数据API 定义: POST api/v4/auth_username{ "username": "emqx_u", "password": "emqx_p"}
########添加用户认证数据##############
POST http://{{hostname}}:{{port}}/api/v4/auth_username HTTP/1.1
Content-Type: {{contentType}}
Authorization: Basic {{userName}}:{{password}}
{ "username": "user", "password": "123456" }
返回
3、更改指定用户名的密码API 定义: PUT api/v4/auth_username/${username}{ "password": "emqx_new_p"}
指定用户名,传递新密码进行更改,再次连接时需要使用新密码进行连接:
###########更改指定用户名的密码#############
PUT http://{{hostname}}:{{port}}/api/v4/auth_username/user HTTP/1.1
Content-Type: {{contentType}}
Authorization: Basic {{userName}}:{{password}}
{ "password": "user" }
返回
4、查看指定用户名信息API 定义: GET api/v4/auth_username/${username}
指定用户名,查看相关用户名、密码信息,注意此处返回的密码是使用配置文件指定哈希方式加密后的密码:
###########查看指定用户名信息#############
GET http://{{hostname}}:{{port}}/api/v4/auth_username/user HTTP/1.1
Content-Type: {{contentType}}
Authorization: Basic {{userName}}:{{password}}
返回
5:删除认证数据API 定义: DELETE api/v4/auth_username/${username}
用以删除指定认证数据
###########删除指定的用户信息#############
DELETE http://{{hostname}}:{{port}}/api/v4/auth_username/user HTTP/1.1
Content-Type: {{contentType}}
Authorization: Basic {{userName}}:{{password}}
返回
2.2.3 MQTTX客户端验证
使用mqtt客户端工具验证使用username连接登录的功能。从 MQTT X: Cross-platform MQTT 5.0 Desktop Client 这个地址下载对应操作系统的mqtt客户端工具。
1、新建连接,参数配置如下
在对应的输入框内输入username和password,clientId这里目前可以随便输入(因为基于clientId的认证功能还没有启用),之后点连接,连接成功。用户名和密码如果输入错误的话是连接不成功的。
2、再次创建一个客户端连接,可作为消息的订阅者,上一个连接作为发布者,如下
3、订阅者添加订阅
订阅完成后
4、上一个客户端连接作为消息的发布者来进行消息的发布
5、查看订阅者是否已经接收到消息
2.3 Client ID 认证
Client ID 认证使用配置文件预设客户端Client ID 与密码,支持通过 HTTP API 管理认证数据。
Client ID 认证不依赖外部数据源,使用上足够简单轻量,使用该种认证方式时需要开启 emqx_auth_clientid 插件,直接在DashBoard中开启即可。
哈希方法
Client ID 认证默认使用 sha256 进行密码哈希加密,可在etc/plugins/emqx_auth_clientid.conf 中更改:
配置哈希方法后,新增的预设认证数据与通过 HTTP API 添加的认证数据将以哈希密文存储在 EMQ X 内置数据库中。
2.3.1 预设认证数据
可以通过配置文件预设认证数据,编辑配置文件: etc/plugins/emqx_auth_clientid.conf
插件启动时将读取预设认证数据并加载到 EMQ X 内置数据库中,节点上的认证数据会在此阶段同步至集群中。
预设认证数据在配置文件中使用了明文密码,出于安全性与可维护性考虑应当避免使用该功能。
2.3.2 HTTP API 管理认证数据
我们使用VSCode来通过EMQ X的API来添加和查看Client ID的认证数据。
1、添加认证数据API 定义: POST api/v4/auth_clientid{ "clientid": "emqx_c", "password": "emqx_p"}
####添加clientId和密码#####
POST http://{{hostname}}:{{port}}/api/v4/auth_clientid HTTP/1.1
Content-Type: {{contentType}}
Authorization: Basic {{userName}}:{{password}}
{ "clientid": "emq-client1", "password": "123456" }
返回
2、查看已经添加的认证数据API 定义: GET api/v4/auth_clientid
#############获取所有详细信息########
GET http://{{hostname}}:{{port}}/api/v4/auth_clientid HTTP/1.1
Content-Type: {{contentType}}
Authorization: Basic {{userName}}:{{password}}
返回
3:更改指定 Client ID 的密码API 定义: PUT api/v4/auth_clientid/${clientid}{ "password": "emqx_new_p"} 指定 Client ID,传递新密码进行更改,再次连接时需要使用新密码进行连接:
#############更改指定 Client ID 的密码########
PUT http://{{hostname}}:{{port}}/api/v4/auth_clientid/emq-client1 HTTP/1.1
Content-Type: {{contentType}}
Authorization: Basic {{userName}}:{{password}}
{ "password": "654321" }
返回
2.3.3 MQTTX客户端验证
使用mqtt客户端工具验证使用Client ID连接登录的功能
此时用户名字段需要输入一个,但是可以随便填写!
2.4 HTTP认证
HTTP 认证使用外部自建 HTTP 应用认证数据源,根据 HTTP API 返回的数据判定认证结果,能够实现复杂的认证鉴权逻辑。启用该功能需要将 emqx_auth_http 插件启用,并且修改该插件的配置文件,在里面指定HTTP认证接口的url。 emqx_auth_http 插件同时还包含了ACL的功能,我们暂时还用不上,通过注释将其禁用。
1:在Dashboard中中开启 emqx_auth_http 插件,同时为了避免误判我们可以停止通过username,clientID 进行认证的插件 emqx_auth_clientid , emqx_auth_username
2.4.1 认证原理
EMQ X 在设备连接事件中使用当前客户端相关信息作为参数,向用户自定义的认证服务发起请求查询权限, 通过返回的 HTTP 响应状态码 (HTTP statusCode) 来处理认证请求。
认证失败:API 返回 4xx 状态码
认证成功:API 返回 200 状态码
忽略认证:API 返回 200 状态码且消息体 ignore
2.4.2 HTTP 请求信息
HTTP API 基础请求信息,配置证书、请求头与重试规则。
加盐规则与哈希方法
HTTP 在请求中传递明文密码,加盐规则与哈希方法取决于 HTTP 应用。
2.4.3 认证请求
进行身份认证时,EMQ X 将使用当前客户端信息填充并发起用户配置的认证查询请求,查询出该客户端在 HTTP 服务器端的认证数据。
打开etc/plugins/emqx_auth_http.conf配置文件,通过修改如下内容:修改完成后需要重启EMQX服务 。
HTTP 请求方法为 GET 时,请求参数将以 URL 查询字符串的形式传递;POST、PUT 请求则将请求参数以普通表单形式提交(content-type 为 x-www-form-urlencoded)。
你可以在认证请求中使用以下占位符,请求时 EMQ X 将自动填充为客户端信息:
推荐使用 POST 与 PUT 方法,使用 GET 方法时明文密码可能会随 URL 被记录到传输过程中的服务器日志中。
2.4.4 认证服务开发
创建基于springboot的应用程序: emqx-demo
1、pom文件
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.6.5
com.jie
emqx-demo
0.0.1-SNAPSHOT
emqx-demo
Demo project for Spring Boot
1.8
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-devtools
runtime
true
org.springframework.boot
spring-boot-configuration-processor
true
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-maven-plugin
org.projectlombok
lombok
2、创建application.yml配置文件并配置
server:
port: 8991
spring:
application:
name: emqx-demo
3、创建Controller:com.jie.emqxdemo.mqtt.AuthController;编写如下
package com.jie.emqxdemo.controller.mqtt;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;
/**
* @description:接受认证请求
* @author: jie
* @time: 2022/3/29 20:57
*/
@RestController
@RequestMapping("/mqtt")
@Slf4j
public class AuthController {
/**
* 用于存储数据 实际开发应该是存储在数据库中
*/
private Map users;
@PostConstruct
public void init() {
//实际的密码应该是密文,mqtt的http认证组件传输过来的密码是明文,我们需要自己进行加密验证
users = new HashMap<>();
users.put("user", "123456");
users.put("emq-client2", "123456");
users.put("emq-client3", "123456");
}
/**
* @description:接受消息 如果属性名对应不上可以用@RequestParam注解做映射
* @author: jie
* @time: 2022/3/29 21:03
*/
@PostMapping("/auth")
public ResponseEntity auth(@RequestParam("clientid") String clientid,
@RequestParam("username") String username,
@RequestParam("password") String password) {
log.info("emqx认证组件调用自定义的认证服务开始认证,clientid={},username={},password= {}", clientid, username, password);
//在此处可以进行复杂也的认证逻辑,但是我们为了演示方便做一个固定操作
String value = users.get(username);
if (StringUtils.isEmpty(value)) {
return new ResponseEntity(HttpStatus.UNAUTHORIZED);
}
if (!value.equals(password)) {
return new ResponseEntity(HttpStatus.UNAUTHORIZED);
}
return new ResponseEntity(HttpStatus.OK);
}
}
2.4.5 MQTTX客户端验证
使用MQTTX客户端工具连接EMQX服务器,如下
我这里不知道为什么一直连接不上,往哪位大佬在评论区指点一二,谢谢!
这个地方的Client-ID随便输入,因为在验证的代码里没有对该字段做校验,之后点连接,发现会连接成功,然后可以去自定义的认证服务中查看控制台输出,证明基于外部的http验证接口生效了。在实际项目开发过程中,HTTP接口校验的代码不会这么简单,账号和密码之类的数据肯定会存在后端数据库中,代码会通过传入的数据和数据库中的数据做校验,如果成功才会校验成功,否则校验失败。
当然EMQ X除了支持我们之前讲过的几种认证方式外,还支持其他的认证方式,比如:MySQL认证、PostgreSQL认证、Redis认证、MongoDB认证,对于其他这些认证方式只需要开启对应的EMQ X插件并且配置对应的配置文件,将对应的数据保存到相应的数据源即可。
3、客户端SDK
在实际项目中我们要针对接MQTT消息代理服务端,从而向其发布消息、订阅消息等来完成我们自己的业务逻辑的开发。EMQ X针对不同的客户端语言都提供了不同的SDK工具包,可以在官网上查看并下下载:
MQTT 客户端 SDK | EMQ (emqx.com)
3.1 Eclipse Paho Java
3.1.1 Paho介绍
Paho Java客户端是用Java编写的MQTT客户端库,用于开发在JVM或其他Java兼容平台(例如Android)上运行的应用程序。
Paho不仅可以对接EMQ X Broker,还可以对接满足符合MQTT协议规范的消息代理服务端,目前Paho可以支持到MQTT5.0以下版本。MQTT3.3.1协议版本基本能满足百分之九十多的接入场景。
Paho Java客户端提供了两个API:
MqttAsyncClient提供了一个完全异步的API,其中活动的完成是通过注册的回调通知的。
MqttClient是MqttAsyncClient周围的同步包装器,在这里,功能似乎与应用程序同步。
3.1.2 Paho实现消息收发
1、找到项目:emqx-demo,添加maven依赖。
org.eclipse.paho
org.eclipse.paho.client.mqttv3
1.2.2
2、编写用于加载yml自定义配置的配置类的代码:com.jie.emqxdemo.properties.Mqttproperties
package com.jie.emqxdemo.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* @description:用于加载yml自定义配置的配置类
* @author: jie
* @time: 2022/3/31 21:12
*/
@Configuration
@ConfigurationProperties(prefix = "mqtt")
@Data
public class Mqttproperties {
private String brokerUrl;
private String clientId;
private String username;
private String password;
@Override
public String toString() {
return "Mqttproperties{" +
"brokerUrl='" + brokerUrl + '\'' +
", clientId='" + clientId + '\'' +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
3、编写消息回调的代码:com.jie.emqxdemo.client.MessageCallback
package com.jie.emqxdemo.client;
import jdk.nashorn.internal.parser.Token;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.springframework.stereotype.Component;
/**
* @description:消息回调
* @author: jie
* @time: 2022/3/31 22:12
*/
@Slf4j
@Component
public class MessageCallback implements MqttCallback {
/**
* @description:丢失对服务端的连接后触发该方法回调,此处可以做一些特殊处理,比如重连
* @author: jie
* @time: 2022/3/31 22:14
*/
@Override
public void connectionLost(Throwable throwable) {
log.info("丢失了对服务的连接");
}
/**
* @description:应用收到消息后出发的回调
* 该方法由mqtt客户端同步调用,在此方法未正确返回之前,不会发送ack确认消息到broker
* 一旦该方法向外抛出了异常客户端将异常关闭,当再次连接时;所有QoS1,QoS2且客户端未进行ack确认的消息都将由 broker服务器再次发送到客户端
* @author: jie
* @time: 2022/3/31 22:15
*/
@Override
public void messageArrived(String s, MqttMessage mqttMessage) throws Exception {
log.info("订阅到了消息;topic={},messageid={},qos={},msg={}",
s,
mqttMessage.getId(),
mqttMessage.getQos(),
new String(mqttMessage.getPayload()));
}
/**
* @description:消息发布完成产生的回调
* @author: jie
* @time: 2022/3/31 22:18
*/
@Override
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
int messageId = iMqttDeliveryToken.getMessageId();
String[] topics = iMqttDeliveryToken.getTopics();
log.info("消息发送完成,messageId={},topics={}",messageId,topics);
}
}
4、编写QOS枚举类:com.jie.emqxdemo.enums.QosEnum
package com.jie.emqxdemo.enums;
/**
* @description:Qos枚举列
* @author: jie
* @time: 2022/3/31 21:54
*/
public enum QosEnum {
QOS0(0),QOS1(1),QOS2(2);
private final int value;
QosEnum(int value){
this.value = value;
}
/**
* @description:获取枚举值
* @author: jie
* @time: 2022/3/31 21:56
*/
public int value(){
return this.value;
}
}
5、在application.yml中添加自定义的配置:
mqtt:
broker-url: tcp://192.168.58.149:1883
client-id: emq-client
username: user
password: 123456
6、客户端封装类:com.jie.emqxdemo.client.
package com.jie.emqxdemo.client;
import com.jie.emqxdemo.enums.QosEnum;
import com.jie.emqxdemo.properties.Mqttproperties;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.nio.charset.StandardCharsets;
/**
* @description:客户端封装类
* @author: jie
* @time: 2022/3/31 21:02
*/
@Component
@Slf4j
public class EmqClient {
private IMqttClient iMqttClient;
/**
* @description:将配置类注入进来
*/
@Autowired
private Mqttproperties mqttproperties;
@Autowired
private MqttCallback mqttCallback;
/**
* @description:初始化
* @author: jie
* @time: 2022/3/31 21:22
*/
@PostConstruct
public void init(){
//持久化机制 持久化到内存 MqttDefaultFilePersistence(持久化到本地的文件系统中)
MqttClientPersistence mqttClientPersistence = new MemoryPersistence();
try {
iMqttClient = new MqttClient(mqttproperties.getBrokerUrl(),mqttproperties.getClientId(),mqttClientPersistence);
} catch (MqttException e) {
log.error("初始化客户端mqttClient对象失败,errormsg={} brokerurl={},clientId= {}",e.getMessage(), mqttproperties.getBrokerUrl(),mqttproperties.getClientId());
}
}
/**
* @description:连接服务端方法
* @author: jie
* @time: 2022/3/31 21:33
*/
public void connect(String username,String password){
//连接选项对象
MqttConnectOptions options = new MqttConnectOptions();
//自动重连
options.setAutomaticReconnect(true);
options.setUserName(username);
options.setPassword(password.toCharArray());
//临时的会话
options.setCleanSession(true);
//方法回调
iMqttClient.setCallback(mqttCallback);
try {
iMqttClient.connect(options);
} catch (MqttException e) {
log.error("连接mqtt broker失败,失败原因:{}",e.getMessage());
}
}
/**
* @description:断开连接
* @author: jie
* @time: 2022/3/31 21:48
*/
@PreDestroy
public void disConnect(){
try {
iMqttClient.disconnect();
} catch (MqttException e) {
log.error("断开连接产生的异常,异常信息{}",e.getMessage());
}
}
/**
* @description:重新连接
* @author: jie
* @time: 2022/3/31 21:51
*/
public void reConnect(){
try {
iMqttClient.reconnect();
} catch (MqttException e) {
log.error("重新连接失败,失原因:{}",e.getMessage());
}
}
/**
* @description:发布消息 topic:主题 msg:消息 qos:qos retain:是否是保留消息
* @author: jie
*/
public void publish(String topic, String msg, QosEnum qos,boolean retain){
MqttMessage mqttMessage = new MqttMessage();
//设置消息体
mqttMessage.setPayload(msg.getBytes(StandardCharsets.UTF_8));
//qos
mqttMessage.setQos(qos.value());
try {
iMqttClient.publish(topic,mqttMessage);
} catch (MqttException e) {
log.error("发布消息失败,失败原因:{},topic={},msg={},qos={},retain={}",e.getMessage(),topic,msg,qos,retain);
}
}
/**
* @description:订阅消息 topicFilter:订阅的主题 qos :qos
* @author: jie
* @time: 2022/3/31 22:04
*/
public void subscribe(String topicFilter,QosEnum qos){
//订阅主题
try {
iMqttClient.subscribe(topicFilter,qos.value());
} catch (MqttException e) {
log.error("订阅主题失败,errormsg={},topicFilter:{},qos:{}",e.getMessage(),topicFilter,qos);
}
}
/**
* @description:取消订阅
* @author: jie
* @time: 2022/3/31 22:08
*/
public void unSubscribe(String topicFilter){
try {
iMqttClient.unsubscribe(topicFilter);
} catch (MqttException e) {
log.error("取消订阅失败,errormsg={},topicFilter={}",e.getMessage(),topicFilter);
}
}
}
7、编写消息发布和订阅的测试,在启动类中添加如下代码(单纯偷懒行为)
package com.jie.emqxdemo;
import com.jie.emqxdemo.client.EmqClient;
import com.jie.emqxdemo.enums.QosEnum;
import com.jie.emqxdemo.properties.Mqttproperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import javax.annotation.PostConstruct;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit;
@SpringBootApplication
public class EmqxDemoApplication {
public static void main(String[] args) {
SpringApplication.run(EmqxDemoApplication.class, args);
}
@Autowired
private EmqClient emqClient;
@Autowired
private Mqttproperties mqttproperties;
@PostConstruct
public void init(){
//连接服务端
emqClient.connect(mqttproperties.getUsername(),mqttproperties.getPassword());
//订阅一个主题
emqClient.subscribe("testtopic/#", QosEnum.QOS2);
//开启一个新的线程,每隔五秒去向 testtopic/123
new Thread(()->{
while (true){
emqClient.publish("testtopic/123","mqtt msg:"+ LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME),QosEnum.QOS2,false);
try {
TimeUnit.SECONDS.sleep(5);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
测试:
在Dashboard中开启使用username进行认证的组件,其他组件停止即可,然后启动项目,查看 控制台输出即可
3.2 MQTT.js
MQTT.js是MQTT协议的客户端JS库,是用JavaScript为node.js和浏览器编写的。
GitHub项目地址: GitHub - mqttjs/MQTT.js: The MQTT client for Node.js and the browser
3.2.1 API列表
大家直接去官方文档查看吧,GitHub项目地址: GitHub - mqttjs/MQTT.js: The MQTT client for Node.js and the browser ,然后往下翻。
3.2.2 MQTT.js实现消息收发
我们写一个HTML
mqtt.js测试
测试:启动项目前将启动类 EmqxDemoApplication 中init 方法上的注解注释掉,启动后访问如下地址查看网页端的输出。
http://localhost:8991/
4. 日志与追踪
4.1 控制日志输出
EMQ X 支持将日志输出到控制台或者日志文件,或者同时使用两者。可在 emqx.conf 中配置 :
log.to = both
log.to 默认值是 both,可选的值为:
offff: 完全关闭日志功能
fifile: 仅将日志输出到文件
console: 仅将日志输出到标准输出(emqx 控制台)
both: 同时将日志输出到文件和标准输出(emqx 控制台)
4.2 日志级别
EMQ X 的日志分 8 个等级, 由低到高分别为:
debug < info < notice < warning < error < critical < alert < emergency
EMQ X 的默认日志级别为 warning,可在 emqx.conf 中修改:
log.level = warning
此配置将所有 log handler 的配置设置为 warning。
4.3 日志文件和日志滚动
EMQ X 的默认日志文件目录在 ./log (zip包解压安装) 或者 /var/log/emqx (二进制包安装)。可在emqx.conf 中配置:
log.dir = log
在文件日志启用的情况下 (log.to = fifile 或 both),日志目录下会有如下几种文件:
emqx.log.N: 以 emqx.log 为前缀的文件为日志文件,包含了 EMQ X 的所有日志消息。比如 emqx.log.1 , emqx.log.2 ...
emqx.log.siz 和 emqx.log.idx: 用于记录日志滚动信息的系统文件。
run_erl.log: 以 emqx start 方式后台启动 EMQ X 时,用于记录启动信息的系统文件。
erlang.log.N: 以 erlang.log 为前缀的文件为日志文件,是以 emqx start 方式后台启动 EMQ X 时,控 制台日志的副本文件。比如 erlang.log.1 , erlang.log.2 ...
可在 emqx.conf 中修改日志文件的前缀,默认为 emqx.log :
log.file = emqx.log
EMQ X 默认在单日志文件超过 10MB 的情况下,滚动日志文件,最多可有 5 个日志文件:第 1 个日志文件为emqx.log.1,第 2 个为 emqx.log.2,并以此类推。
当最后一个日志文件也写满 10MB 的时候,将从序号最小的日志的文件开始覆盖。文件大小限制和最大日志文件个数可在 emqx.conf 中修改:
log.rotation.size = 10MB
log.rotation.count = 5
4.4 针对日志级别输出日志文件
如果想把大于或等于某个级别的日志写入到单独的文件,可以在 emqx.conf 中配置 log..file : 将 info 及info 以上的日志单独输出到 info.log.N 文件中:
log.info.file = info.log
将 error 及 error 以上的日志单独输出到 error.log.N 文件中
log.error.file = error.log
4.5 日志格式
可在 emqx.conf 中修改单个日志消息的最大字符长度,如长度超过限制则截断日志消息并用 ... 填充。默认不限制长度:
将单个日志消息的最大字符长度设置为 8192:
log.chars_limit = 8192
日志消息的格式为(各个字段之间用空格分隔)
date time level client_info module_info msg
date: 当地时间的日期。格式为:YYYY-MM-DD
time: 当地时间,精确到毫秒。格式为:hh:mm:ss.ms
level: 日志级别,使用中括号包裹。格式为:[Level]
client_info: 可选字段,仅当此日志消息与某个客户端相关时存在。其格式为:ClientId@Peername 或ClientId 或 Peername
module_info: 可选字段,仅当此日志消息与某个模块相关时存在。其格式为:[Module Info]
msg: 日志消息内容。格式任意,可包含空格。
日志消息举例
2022-04-1 16:10:03.872 [debug] <<"mqttjs_9e49354bb3">>@127.0.0.1:57105 [MQTT/WS] SEND CONNACK(Q0, R0, D0, AckFlags=0, ReasonCode=0)
此日志消息里各个字段分别为:
date: 2022-04-1
time: 16:10:03.872
level: [debug]
client_info: <<"mqttjs_9e49354bb3">>@127.0.0.1:57105
module_info: [MQTT/WS]
msg: SEND CONNACK(Q0, R0, D0, AckFlags=0, ReasonCode=0)
2022-04-1 16:10:08.474 [warning] [Alarm Handler] New Alarm: system_memory_high_watermark, Alarm Info: []
此日志消息里各个字段分别为:
注意此日志消息中,client_info 字段不存在。
4.6 日志级别和log handlers
EMQ X 使用了分层的日志系统,在日志级别上,包括全局日志级别 (primary log level)、以及各 log hanlder的日志级别。
[Primary Level] -- global log level and filters
/ \
[Handler 1] [Handler 2] -- log levels and filters at each handler
log handler 是负责日志处理和输出的工作进程,它由 log handler id 唯一标识,并负有如下任务:
接收什么级别的日志
如何过滤日志消息
将日志输出到什么地方
我们来看一下 emqx 默认安装的 log handlers:
emqx_ctl log handlers list
fifile: 负责输出到日志文件的 log handler。它没有设置特殊过滤条件,即所有日志消息只要级别满足要求就输出。输出目的地为日志文件。
default: 负责输出到控制台的 log handler。它没有设置特殊过滤条件,即所有日志消息只要级别满足要求就输出。输出目的地为控制台。
ssl_handler: ssl 的 log handler。它的过滤条件设置为当日志是来自 ssl 模块时输出。输出目的地为控制台。
日志消息输出前,首先检查消息是否高于 primary log level,日志消息通过检查后流入各 log handler,再检查各 handler 的日志级别,如果日志消息也高于 handler level,则由对应的 handler 执行相应的过滤条件,过滤条件通过则输出。
设想一个场景,假设 primary log level 设置为 info ,log handler default (负责输出到控制台) 的级别设置为debug ,log handler file (负责输出到文件) 的级别设置为 warning :
虽然 console 日志是 debug 级别,但此时 console 日志只能输出 info 以及 info 以上的消息,因为经过primary level 过滤之后,流到 default 和 fifile 的日志只剩下 info 及以上的级别;
emqx.log.N 文件里面,包含了 warning 以及 warning 以上的日志消息。
在日志级别小节中提到的 log.level 是修改了全局的日志级别。这包括 primary log level 和各个 handlers的日志级别,都设置为了同一个值。
Primary Log Level 相当于一个自来水管道系统的总开关,一旦关闭则各个分支管道都不再有水流通过。这个机制保证了日志系统的高性能运作。
4.7 运行时修改日志级别
可以使用 EMQ X 的命令行工具 emqx_ctl 在运行时修改 emqx 的日志级别:
修改全局日志级别:
例如,将 primary log level 以及所有 log handlers 的级别设置为 debug:
emqx_ctl log set-level debug
修改主日志级别:
例如,将 primary log level 设置为 debug:
emqx_ctl log primary-level debug
修改某个log handler的日志级别:
例如,将 log handler file 设置为 debug:
emqx_ctl log handlers set-level file debug
4.8 日志追踪
EMQ X 支持针对 ClientID 或 Topic 过滤日志并输出到文件。在使用日志追踪功能之前,必须将 primary log level 设置为 debug:
emqx_ctl log primary-level debug 1111
开启 ClientID 日志追踪,将所有 ClientID 为 emq-demo 的日志都输出到log/my_client.log:
emqx_ctl log primary-level debug debug
emqx_ctl trace start client emq-demo log/emq-demo.log
开启 Topic 日志追踪,将主题能匹配到 'testtopic/#' 的消息发布日志输出到 log/topic_testtopic.log:
emqx_ctl log primary-level debug debug
emqx_ctl trace start topic 'testtopic/#' log/topic_testtopic.log trace topic testtopic/# successfully 1234512345
提示:即使 emqx.conf 中, log.level 设置为 error,使用消息追踪功能仍然能够打印出某 client 或 topic 的 debug 级别的信息。这在生产环境中非常有用。
你可能感兴趣的:(物联网,EMQX)
Python 与Java 开发人形机器人远程控制APP
Geeker-2025
python java
开发一款人行开发机器人远程控制App是一个复杂且高度技术性的项目。该项目涉及多个技术领域,包括前端开发、后端开发、物联网(IoT)通信、实时数据处理、数据加密、安全性保障等。使用Python和Java联合开发可以充分利用每种语言的优势,构建一个高性能、可扩展且功能丰富的应用。以下是一个高层次的设计概述,涵盖主要的技术栈和功能模块,并提供使用Python和Java联合开发的示例。##技术栈概述###
《ArkTS鸿蒙应用开发入门到实战》—新手小白学习鸿蒙的推荐工具书!
心态还需努力呀
HarmonyOS harmonyos 华为 鸿蒙应用开发入门到实战 ArkTS
《ArkTS鸿蒙应用开发入门到实战》—新手小白学习鸿蒙的推荐工具书!在科技日新月异的今天,鸿蒙操作系统(HarmonyOS)作为华为推出的全新操作系统,正迅速进入越来越多的智能设备,成为物联网和智能硬件领域的重要平台。如果你是鸿蒙开发的新手,面对众多的学习资源和技术文档,可能会感到无从下手。别担心,《ArkTS鸿蒙应用开发入门到实战》这本书,正是为你提供的一本最佳入门工具书,帮助你轻松踏入鸿蒙应用
边缘AI推理模型更新的秘密武器——Nginx的在线升级魔法
墨夶
Nginx学习资料1 人工智能 nginx 运维
在当今快速发展的物联网和边缘计算时代,如何确保部署于边缘节点上的AI推理模型能够及时、高效地进行在线更新,成为了技术团队面临的一项重要挑战。传统的离线更新方式不仅耗时费力,而且可能导致服务中断,影响用户体验。为此,我们探索了一种基于Nginx的创新解决方案,它允许我们在不影响现有服务的前提下,平滑地完成模型版本迭代。本文将详细介绍这一过程,并分享具体实现方法及代码示例。1.Nginx简介及其优势N
LeetCode - #219 存在重复元素 II
网罗开发
Swift vue.js leetcode 算法
网罗开发(小红书、快手、视频号同名) 大家好,我是展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、HarmonyOS、Java、Python等方向。在移动端开发、鸿蒙开发、物联网、嵌入式、云原生、开源等领域有深厚造诣。图书作者:《ESP32-C3物联网工程开发实战》图书作者:《SwiftUI入门,进阶与实战》超级个体:CO
AI 驱动的智慧大脑:打造企业动态知识库,开启高效管理新时代
网罗开发
人工智能 AI 大模型 深度学习 人工智能
网罗开发(小红书、快手、视频号同名) 大家好,我是展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、HarmonyOS、Java、Python等方向。在移动端开发、鸿蒙开发、物联网、嵌入式、云原生、开源等领域有深厚造诣。图书作者:《ESP32-C3物联网工程开发实战》图书作者:《SwiftUI入门,进阶与实战》超级个体:CO
【北京迅为】iTOP-RK3568OpenHarmony系统南向驱动开发-第5章 UART接口运作机制
北京迅为
鸿蒙 harmonyos 鸿蒙 嵌入式硬件 人工智能 RK3568
瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和MaliG522EE图形处理器。RK3568支持4K解码和1080P编码,支持SATA/PCIE/USB3.0外围接口。RK3568内置独立NPU,可用于轻量级人工智能应用。RK3568支持安卓11和linux系统,主要面向物联网网关、NVR存储、工控平板、工业检测、工控盒、卡拉OK
Java在物联网(IoT)中的应用研究
向哆哆
Java入门到精通 java 物联网 python
Java在物联网(IoT)中的应用研究物联网(InternetofThings,简称IoT)是一个日益增长的领域,涉及将各种设备连接到互联网,实现数据交换和智能控制。Java作为一种跨平台、面向对象的编程语言,在物联网应用中有着广泛的应用场景。本文将探讨Java在物联网中的应用,并通过代码实例展示如何在IoT设备中使用Java进行开发。1.物联网简介与挑战物联网(IoT)通过将传感器、执行器等设备
新一代信息技术:从技术范畴到未来趋势的全景洞察
漫谈网络
IT前沿视界 科普 网络
新一代信息技术(NewGenerationInformationTechnology)是当前全球科技革命和产业变革的核心驱动力之一,也是各国政策文件中重点支持的战略性技术领域。它并非单一技术,而是一系列前沿信息技术的融合与集成,旨在推动数字化转型、智能化升级和经济社会高质量发展。以下是其核心构成和特点:核心技术范畴5G/6G通信技术高速率、低时延、大连接的新一代移动通信网络,为物联网、工业互联网等
T23N 君正(Ingenic)T系列芯片是专为智能视频和物联网应用设计的高性能、低功耗处理器 提供软硬件资料及样品测试
li15817260414
音视频 物联网
T23N是一款由君正(Ingenic)推出的智能视频应用处理器(SoC),广泛应用于移动摄像机、安全监控、视频通话和视频分析等领域。该芯片采用创新架构,满足高性能计算和高质量图像视频编码的需求。主要特性:处理器:T23N配备XBurst®CPU核心,主频高达1.2GHz,内置16KB指令缓存、16KB数据缓存和64KB二级缓存,支持全功能内存管理单元(MMU),适用于操作系统相关任务。视频处理:集
物联网智能项目实战:从概念到实现
程序猿!=程序员
物联网
引言物联网(IoT)正在以前所未有的速度改变着我们的生活,从智能家居到工业自动化,物联网的应用无处不在。作为一名嵌入式工程师,掌握物联网技术并将其应用于实际项目中,是提升自身竞争力的关键。本文将带你从零开始,一步步完成一个物联网智能项目的开发,涵盖项目构思、硬件选型、软件开发、云平台接入等关键环节。一、项目构思首先,我们需要明确项目的目标和功能。以下是一些物联网智能项目的灵感来源:智能家居:智能灯
嵌入式的应用领域、现状及未来趋势
Lemon__L
嵌入式 嵌入式 现状/趋势
嵌入式的应用领域、现状及未来趋势随着科技进步,嵌入式的出现,以及人们对生活质量,产品的智能化,成本的要求等,以及国家对与物联网、电子、科技的扶持,大量的电子产品都促使嵌入式的快速发展。使用嵌入式的产品如我们常用的手机、平板电脑、电子字典、可视电话、数字相机(DC)、数字摄像机(DV)、U-Disk、机顶盒(SetTopBox)、高清电视(HDTV)、游戏机、智能玩具、交换机、路由器、数控设备或仪表
嵌入式边缘计算:融合创新与未来展望
嵌入式大圣
边缘计算 人工智能 大数据
本文深入探讨了嵌入式边缘计算。首先解析了其概念,指出它是将计算和数据存储能力嵌入边缘设备以实现本地数据处理。阐述了其低延迟、高可靠性、节省带宽、隐私保护和高效节能等技术特点。接着介绍了关键技术,包括嵌入式系统设计、边缘计算架构、通信技术和数据分析与处理技术。在应用领域方面,涵盖了工业物联网、智能交通、智能家居和医疗保健等。最后展望了未来发展趋势,包括技术融合与创新、应用拓展与深化以及生态系统的完善
KaiwuDB 亮相第二十四届中国国际工业博览会
数据库
9月24-28日,以“工业聚能,新质领航”为主题的2024第二十四届中国国际工业博览会(以下简称“工博会”)在国家会展中心(上海)盛大召开,吸引来自全球28个国家和地区2600家参展商,围绕新一代信息技术与应用、智慧能源、新能源与智能网联汽车、机器人等9大专业主题进行集中展示。KaiwuDB受邀亮相大会,以“PoweredbyKaiwuDB”为核心理念打造的工业物联网、数字能源、分布式储能、车联网
构建智慧校园:推动教育现代化的重要路径
智慧校园-合肥自友科技
智慧校园 数字化校园 智慧校园平台 智慧校园 智慧校园系统 智慧校园平台 智慧校园建设 智慧校园软件 智慧校园方案 智慧校园厂商
随着信息技术的飞速发展,智慧校园作为教育领域的新趋势,正逐渐成为推动教育现代化的重要力量。智慧校园不仅是一种物理空间的升级,更是一种教育理念和实践方式的革新。它强调利用大数据、人工智能、物联网等前沿技术,实现教学过程的智能化、个性化与高效化。智慧校园的核心在于智能硬件设施的广泛部署,如智能教室、电子白板、智能图书馆等,这些设备不仅能够提供更为便捷、高效的教与学环境,还能够收集并分析大量数据,为优化
基于数据采集网关的医院能耗在线监测系统
物通博联网关
自动化 PLC远程上下载 工业智能网关 数据可视化云平台 工业物联网
医院是重要的公共设施。为了满足医务人员、病人及家属的工作生活需求,产生越来越高的能源消耗,对医院运营带来一定的负担。因此,在提高医疗水平和医疗环境的同时,加强能源管理,提高能源利用率,减少能源浪费,远程监控能耗数据,成为管理部门的必须解决的问题,对社会经济、环境发展都有重要的意义。医院能耗在线监测系统以数据采集网关和物联网云平台为核心,电表水表等设备数据采集上来并通过统一协议和网络传输至云平台,为
物联网串口综述
reset2021
物联网 物联网
串口(SerialPort)是一种用于设备之间传输数据的接口,其特点是以一条信号线依次传输数据位,因此它是一种“serial”通信方式。以下是对串口的一些关键点进行总结:1.基本概念串口通信:是一种基于RS-232(或RS-485、RS-422等标准)的同步或异步通信接口,主要用于设备间的数据传输。串口接口:通常使用DB9或DB25连接器,常见于电脑、嵌入式系统、工业控制设备等。2.工作原理数据在
物联网在智慧医院中的应用与规划
罗思付之技术屋
综合技术探讨及方案专栏 物联网
摘要随着信息技术的快速发展,物联网技术在医院中的应用已经成为医疗领域的重要研究方向。基于医院物联网应用要求,提出一个符合智慧医院建设要求的物联网规划方法和技术架构,并提出了未来医院物联网的规划建议。引言随着医疗信息化的推进,医院物联网作为解决医疗领域问题的有效手段,受到了广泛的关注。医院物联网通过将传感器、设备和信息系统连接起来,实现对医疗建筑环境、医疗设备和医疗服务过程的实时监测和管理,提高医疗
美畅物联丨为什么在物联网应用中,通常更倾向于使用 MQTT 而不是 HTTP?
畅联云平台
物联网 http 网络协议
最近,我们的后台收到了许多用户的私信咨询,其中一个问题便是:在物联网(IoT)应用中,为何通常更倾向于使用MQTT而非HTTP呢?今天我们就来探讨一下这个话题。前面在介绍MOTT协议的时候我们就已经提到过,MQTT属于一种轻量级的消息传输协议,其协议头相当简洁。正常情况下,MQTT的固定头部仅有2个字节,用来标识消息类型、QoS(服务质量)等级等基本信息。在某些特定的消息类型里,也许会存在可变头部
美畅物联丨物联网平台的标准化之路:物模型设计的创新及应用
畅联云平台
物联网
随着物联网(IoT)技术以前所未有的迅猛之势蓬勃发展,海量的物联网终端与应用纷纷接入,这不可避免地引发了数据与应用层面的异构化难题,进而形成了复杂且多变的碎片化问题。物联网感知数据因其具备多源异构的显著特性,极大程度地增加了数据识别、精准解析以及深度挖掘的重重困难,致使不同物联网应用之间的数据共享仿佛筑起了高耸的壁垒,协同合作的推进也举步维艰。此外,鉴于设备制造商所遵循的生产标准各不相同,设备接入
算力革新引领数字中国智能跃迁
智能计算研究中心
其他
内容概要算力作为数字经济的核心驱动力,正通过架构创新与场景融合加速重构技术生态。当前算力体系呈现三大演进方向:异构计算突破传统芯片性能瓶颈,实现CPU、GPU、FPGA等多元架构的协同调度;边缘计算推动工业设备、物联网终端等场景的实时响应能力提升,形成“云-边-端”三级计算网络;量子计算则在加密通信、药物研发等领域展现颠覆性潜力,其物理比特操控精度已达实用化临界点。技术方向核心特征典型应用场景异构
AIoT安全与隐私自动化建设:实践与展望
ITPUB-微风
安全 自动化 运维
随着物联网(IoT)的快速发展,AIoT(人工智能物联网)已成为新时代的技术趋势。然而,随着设备的增多和应用的广泛,AIoT的安全与隐私问题也日益凸显。本文将探讨AIoT安全与隐私自动化建设的实践与展望。一、背景AIoT设备数量的激增带来了诸多安全挑战,如僵尸网络、中间人攻击、隐私泄露等。这些威胁不仅影响设备的正常运行,还可能对用户隐私造成严重损害。因此,建立有效的AIoT安全与隐私保护机制迫在眉
BY组态-低代码web可视化组件
万维——组态
低代码 前端 物联网 运维 数学建模 编辑器
简介BY组态是集实时数据展示、动态交互等一体的全功能可视化平台。帮助物联网、工业互联网、电力能源、水利工程、智慧农业、智慧医疗、智慧城市等场景快速实现数字孪生、大屏可视化、Web组态、SCADA等解决方案。具有实时监控、多样、变化、动态交互、高效、可扩展、支持自动算法、跨平台等特点,最大程度减少研发和运维的成本,并致力于普通业务人员0代码开发实现数字孪生、大屏可视化、Web组态、SCADA等解决方
数据精简的魔法:打造极速接口响应!
喵手
零基础学Java Java 接口响应
全文目录:开篇语前言目录精简数据传输的重要性举个栗子️常用的精简策略1.字段选择:只传递必需字段示例代码:2.数据分页:控制数据的数量示例代码:3.压缩传输:小数据大世界案例分析:从冗余到高效1️⃣初始设计2️⃣优化设计拓展延伸:在不同场景中的应用企业应用移动端应用物联网(IoT)设备结语文末开篇语哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云/阿里云/华为云/51CTO;欢
大模型成本优化实战:从分布式训练到量化剪枝,轻松降低AI计算开销
网罗开发
AI 大模型 人工智能 机器学习 深度学习
网罗开发(小红书、快手、视频号同名) 大家好,我是展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、HarmonyOS、Java、Python等方向。在移动端开发、鸿蒙开发、物联网、嵌入式、云原生、开源等领域有深厚造诣。图书作者:《ESP32-C3物联网工程开发实战》图书作者:《SwiftUI入门,进阶与实战》超级个体:CO
高并发微服务日志管理:ELK、Loki、Fluentd 终极对决与实战指南
网罗开发
java集 后端 云原生 微服务 elk 架构
网罗开发(小红书、快手、视频号同名) 大家好,我是展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、HarmonyOS、Java、Python等方向。在移动端开发、鸿蒙开发、物联网、嵌入式、云原生、开源等领域有深厚造诣。图书作者:《ESP32-C3物联网工程开发实战》图书作者:《SwiftUI入门,进阶与实战》超级个体:CO
在 SQLite 中使用 SpatiaLite 实现地理空间数据自动化读写
高堂明镜悲白发
sqlite 自动化 数据库 GIS
地理空间数据(如坐标点、区域边界)的存储与查询是物联网、位置服务等领域的常见需求。本文提供一套简洁的解决方案,利用SQLite和SpatiaLite扩展,通过触发器和视图实现以下目标:写入简化:直接插入人类可读的坐标文本(如POINT(116.439.9)),自动转为二进制存储。读取简化:查询时自动返回坐标文本,无需手动调用转换函数。代码友好:便于与Python、Java等后端程序集成,隐藏底层空
【奥卡姆剃刀原理-如何理解云计算和边缘计算 关键字摘取】
严文文-Chris
科学思维修炼 云计算 边缘计算 人工智能
云计算可能还是你相对熟悉的概念。通俗来说,就是把计算任务从本地挪到远程,往往是挪到一个大的计算中心。在那里完成计算之后,再把计算结果返回本地。这样本地就不用部署很强的硬件搞计算了。而边缘计算的介绍大都说,这是把一部分计算任务放在分散各处的本地去完成,这样可以减少云服务器的计算压力,也能缓解传输带宽上的压力。然后再套上其他流行词,比如边缘计算特别适用于物联网、车联网、AR/VR等应用场景。奥卡姆剃刀
如今传统企业如何做数字化转型?
年少有为2025
saas 小程序开发 big data 人工智能 大数据 产品运营 架构
什么是数字化转型?“数字化转型”实际上就是对业务过程进行的重塑,通过重塑使其默认就更加适应更全面的在线环境,从最终用户的接触到后端的办公室工作,全面实现无需人工接入的过程自动化。广义上的数字化,强调的是数字技术对商业网的重塑,信息技术能力。不只是单纯的解决企业的降本增效的问题,而是成为赋能企业商业模式创新和突破的核心力量。“数字化转型就是利用数字化技术,如云计算、大数据、人工智能、物联网、区块链等
运维案例之记一次Kubernetes集群证书过期或延期操作处理实践指南
全栈工程师修炼指南
云原生落地实用指南 kubernetes 运维 docker 容器 云原生
欢迎关注「WeiyiGeek」公众号点击下方卡片即可关注我哟!设为「星标⭐」每天带你基础入门到进阶实践再到放弃学习!涉及网络安全运维、应用开发、物联网IOT、学习路径、个人感悟等知识“花开堪折直须折,莫待无花空折枝。”作者主页:[https://www.weiyigeek.top]作者博客:[https://blog.weiyigeek.top]作者答疑学习交流群:
腾讯云 TDMQ 产品家族新成员:消息队列 MQTT 版全新发布!
腾讯云消息队列mqtt
导语自2024年12月27日起,腾讯云消息队列团队正式发布TDMQ产品家族的新成员:TDMQMQTT版。这款新产品旨在满足物联网和车联网场景下日益增长的应用需求,为企业的技术变革和产业升级提供有力支持。TDMQMQTT版推出的背景当前腾讯云消息队列产品家族已拥有多个子产品:CKafka作为业界高吞吐的标杆,广泛地用于离线消息的场景,如大规模日志收集等类似的业务。RocketMQ以其低延时和高并发的
java类加载顺序
3213213333332132
java
package com.demo;
/**
* @Description 类加载顺序
* @author FuJianyong
* 2015-2-6上午11:21:37
*/
public class ClassLoaderSequence {
String s1 = "成员属性";
static String s2 = "
Hibernate与mybitas的比较
BlueSkator
sql Hibernate 框架 ibatis orm
第一章 Hibernate与MyBatis
Hibernate 是当前最流行的O/R mapping框架,它出身于sf.net,现在已经成为Jboss的一部分。 Mybatis 是另外一种优秀的O/R mapping框架。目前属于apache的一个子项目。
MyBatis 参考资料官网:http:
php多维数组排序以及实际工作中的应用
dcj3sjt126com
PHP usort uasort
自定义排序函数返回false或负数意味着第一个参数应该排在第二个参数的前面, 正数或true反之, 0相等usort不保存键名uasort 键名会保存下来uksort 排序是对键名进行的
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8&q
DOM改变字体大小
周华华
前端
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml&q
c3p0的配置
g21121
c3p0
c3p0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。c3p0的下载地址是:http://sourceforge.net/projects/c3p0/这里可以下载到c3p0最新版本。
以在spring中配置dataSource为例:
<!-- spring加载资源文件 -->
<bean name="prope
Java获取工程路径的几种方法
510888780
java
第一种:
File f = new File(this.getClass().getResource("/").getPath());
System.out.println(f);
结果:
C:\Documents%20and%20Settings\Administrator\workspace\projectName\bin
获取当前类的所在工程路径;
如果不加“
在类Unix系统下实现SSH免密码登录服务器
Harry642
免密 ssh
1.客户机
(1)执行ssh-keygen -t rsa -C "xxxxx@xxxxx.com"生成公钥,xxx为自定义大email地址
(2)执行scp ~/.ssh/id_rsa.pub root@xxxxxxxxx:/tmp将公钥拷贝到服务器上,xxx为服务器地址
(3)执行cat
Java新手入门的30个基本概念一
aijuans
java java 入门 新手
在我们学习Java的过程中,掌握其中的基本概念对我们的学习无论是J2SE,J2EE,J2ME都是很重要的,J2SE是Java的基础,所以有必要对其中的基本概念做以归纳,以便大家在以后的学习过程中更好的理解java的精髓,在此我总结了30条基本的概念。 Java概述: 目前Java主要应用于中间件的开发(middleware)---处理客户机于服务器之间的通信技术,早期的实践证明,Java不适合
Memcached for windows 简单介绍
antlove
java Web windows cache memcached
1. 安装memcached server
a. 下载memcached-1.2.6-win32-bin.zip
b. 解压缩,dos 窗口切换到 memcached.exe所在目录,运行memcached.exe -d install
c.启动memcached Server,直接在dos窗口键入 net start "memcached Server&quo
数据库对象的视图和索引
百合不是茶
索引 oeacle数据库 视图
视图
视图是从一个表或视图导出的表,也可以是从多个表或视图导出的表。视图是一个虚表,数据库不对视图所对应的数据进行实际存储,只存储视图的定义,对视图的数据进行操作时,只能将字段定义为视图,不能将具体的数据定义为视图
为什么oracle需要视图;
&
Mockito(一) --入门篇
bijian1013
持续集成 mockito 单元测试
Mockito是一个针对Java的mocking框架,它与EasyMock和jMock很相似,但是通过在执行后校验什么已经被调用,它消除了对期望 行为(expectations)的需要。其它的mocking库需要你在执行前记录期望行为(expectations),而这导致了丑陋的初始化代码。
&nb
精通Oracle10编程SQL(5)SQL函数
bijian1013
oracle 数据库 plsql
/*
* SQL函数
*/
--数字函数
--ABS(n):返回数字n的绝对值
declare
v_abs number(6,2);
begin
v_abs:=abs(&no);
dbms_output.put_line('绝对值:'||v_abs);
end;
--ACOS(n):返回数字n的反余弦值,输入值的范围是-1~1,输出值的单位为弧度
【Log4j一】Log4j总体介绍
bit1129
log4j
Log4j组件:Logger、Appender、Layout
Log4j核心包含三个组件:logger、appender和layout。这三个组件协作提供日志功能:
日志的输出目标
日志的输出格式
日志的输出级别(是否抑制日志的输出)
logger继承特性
A logger is said to be an ancestor of anothe
Java IO笔记
白糖_
java
public static void main(String[] args) throws IOException {
//输入流
InputStream in = Test.class.getResourceAsStream("/test");
InputStreamReader isr = new InputStreamReader(in);
Bu
Docker 监控
ronin47
docker监控
目前项目内部署了docker,于是涉及到关于监控的事情,参考一些经典实例以及一些自己的想法,总结一下思路。 1、关于监控的内容 监控宿主机本身
监控宿主机本身还是比较简单的,同其他服务器监控类似,对cpu、network、io、disk等做通用的检查,这里不再细说。
额外的,因为是docker的
java-顺时针打印图形
bylijinnan
java
一个画图程序 要求打印出:
1.int i=5;
2.1 2 3 4 5
3.16 17 18 19 6
4.15 24 25 20 7
5.14 23 22 21 8
6.13 12 11 10 9
7.
8.int i=6
9.1 2 3 4 5 6
10.20 21 22 23 24 7
11.19
关于iReport汉化版强制使用英文的配置方法
Kai_Ge
iReport汉化 英文版
对于那些具有强迫症的工程师来说,软件汉化固然好用,但是汉化不完整却极为头疼,本方法针对iReport汉化不完整的情况,强制使用英文版,方法如下:
在 iReport 安装路径下的 etc/ireport.conf 里增加红色部分启动参数,即可变为英文版。
# ${HOME} will be replaced by user home directory accordin
[并行计算]论宇宙的可计算性
comsci
并行计算
现在我们知道,一个涡旋系统具有并行计算能力.按照自然运动理论,这个系统也同时具有存储能力,同时具备计算和存储能力的系统,在某种条件下一般都会产生意识......
那么,这种概念让我们推论出一个结论
&nb
用OpenGL实现无限循环的coverflow
dai_lm
android coverflow
网上找了很久,都是用Gallery实现的,效果不是很满意,结果发现这个用OpenGL实现的,稍微修改了一下源码,实现了无限循环功能
源码地址:
https://github.com/jackfengji/glcoverflow
public class CoverFlowOpenGL extends GLSurfaceView implements
GLSurfaceV
JAVA数据计算的几个解决方案1
datamachine
java Hibernate 计算
老大丢过来的软件跑了10天,摸到点门道,正好跟以前攒的私房有关联,整理存档。
-----------------------------华丽的分割线-------------------------------------
数据计算层是指介于数据存储和应用程序之间,负责计算数据存储层的数据,并将计算结果返回应用程序的层次。J
&nbs
简单的用户授权系统,利用给user表添加一个字段标识管理员的方式
dcj3sjt126com
yii
怎么创建一个简单的(非 RBAC)用户授权系统
通过查看论坛,我发现这是一个常见的问题,所以我决定写这篇文章。
本文只包括授权系统.假设你已经知道怎么创建身份验证系统(登录)。 数据库
首先在 user 表创建一个新的字段(integer 类型),字段名 'accessLevel',它定义了用户的访问权限 扩展 CWebUser 类
在配置文件(一般为 protecte
未选之路
dcj3sjt126com
诗
作者:罗伯特*费罗斯特
黄色的树林里分出两条路,
可惜我不能同时去涉足,
我在那路口久久伫立,
我向着一条路极目望去,
直到它消失在丛林深处.
但我却选了另外一条路,
它荒草萋萋,十分幽寂;
显得更诱人,更美丽,
虽然在这两条小路上,
都很少留下旅人的足迹.
那天清晨落叶满地,
两条路都未见脚印痕迹.
呵,留下一条路等改日再
Java处理15位身份证变18位
蕃薯耀
18位身份证变15位 15位身份证变18位 身份证转换
15位身份证变18位,18位身份证变15位
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
蕃薯耀 201
SpringMVC4零配置--应用上下文配置【AppConfig】
hanqunfeng
springmvc4
从spring3.0开始,Spring将JavaConfig整合到核心模块,普通的POJO只需要标注@Configuration注解,就可以成为spring配置类,并通过在方法上标注@Bean注解的方式注入bean。
Xml配置和Java类配置对比如下:
applicationContext-AppConfig.xml
<!-- 激活自动代理功能 参看:
Android中webview跟JAVASCRIPT中的交互
jackyrong
JavaScript html android 脚本
在android的应用程序中,可以直接调用webview中的javascript代码,而webview中的javascript代码,也可以去调用ANDROID应用程序(也就是JAVA部分的代码).下面举例说明之:
1 JAVASCRIPT脚本调用android程序
要在webview中,调用addJavascriptInterface(OBJ,int
8个最佳Web开发资源推荐
lampcy
编程 Web 程序员
Web开发对程序员来说是一项较为复杂的工作,程序员需要快速地满足用户需求。如今很多的在线资源可以给程序员提供帮助,比如指导手册、在线课程和一些参考资料,而且这些资源基本都是免费和适合初学者的。无论你是需要选择一门新的编程语言,或是了解最新的标准,还是需要从其他地方找到一些灵感,我们这里为你整理了一些很好的Web开发资源,帮助你更成功地进行Web开发。
这里列出10个最佳Web开发资源,它们都是受
架构师之面试------jdk的hashMap实现
nannan408
HashMap
1.前言。
如题。
2.详述。
(1)hashMap算法就是数组链表。数组存放的元素是键值对。jdk通过移位算法(其实也就是简单的加乘算法),如下代码来生成数组下标(生成后indexFor一下就成下标了)。
static int hash(int h)
{
h ^= (h >>> 20) ^ (h >>>
html禁止清除input文本输入缓存
Rainbow702
html 缓存 input 输入框 change
多数浏览器默认会缓存input的值,只有使用ctl+F5强制刷新的才可以清除缓存记录。
如果不想让浏览器缓存input的值,有2种方法:
方法一: 在不想使用缓存的input中添加 autocomplete="off";
<input type="text" autocomplete="off" n
POJO和JavaBean的区别和联系
tjmljw
POJO java beans
POJO 和JavaBean是我们常见的两个关键字,一般容易混淆,POJO全称是Plain Ordinary Java Object / Pure Old Java Object,中文可以翻译成:普通Java类,具有一部分getter/setter方法的那种类就可以称作POJO,但是JavaBean则比 POJO复杂很多, Java Bean 是可复用的组件,对 Java Bean 并没有严格的规
java中单例的五种写法
liuxiaoling
java 单例
/**
* 单例模式的五种写法:
* 1、懒汉
* 2、恶汉
* 3、静态内部类
* 4、枚举
* 5、双重校验锁
*/
/**
* 五、 双重校验锁,在当前的内存模型中无效
*/
class LockSingleton
{
private volatile static LockSingleton singleton;
pri