mqtt 发送消息过多_物联网宠儿mqtt.js那些事儿

2023-10-29

常见的mq有Kafka,RocketMQ和RabbitMQ,大家也很常见。 前者很常见,MQTT是什么呢?MQTT属于IoT也就是物联网的概念。

常见的mq有Kafka,RocketMQ和RabbitMQ,大家也很常见。MQTT是什么呢?

Kafka,RocketMQ和RabbitMQ属于微服务间的mq,而MQTT则属于IoT也就是物联网的概念。

mqtt.js是MQTT在nodejs端的实现。vue技术栈下的前端也可用。

mqtt.js官方为微信小程序和支付宝小程序也做了支持。微信小程序的MQTT协议名为 wxs ,支付宝小程序则是 alis 。

如果还是一脸懵逼,那么就跟随我通过mqtt.js去认识一下这个物联网领域的宠儿吧。

  • 什么是微消息队列?
  • MQTT关键名词解释
  • P2P消息和Pub/Sub消息
  • 封装的mqtt.js通用class
  • 客户端发包函数sendPacket
  • 客户端连接 mqtt.connect()
  • 订阅topic mqtt.Client#subscribe()
  • 发送消息 mqtt.Client#publish()
  • 接收消息 mqtt.Client#“message”事件

什么是微消息队列?

消息队列一般分为两种:

  • 微服务消息队列(微服务间信息传递,典型代表有RabbitMQ,Kafka,RocketMQ)
  • 物联网消息队列(物联网端与云端消息传递,代表有MQTT)

目前我实践过的,也就是我们本篇博文深入分析的,是物联网消息队列的mqtt.js。

传统的消息队列(微服务间信息传递)
传统的微服务间(多个子系统服务端间)消息队列是一种非常常见的服务端间消息传递的方式。

典型代表有:RabbitMQ,Kafka,RocketMQ。

阿里云官网拥有AMQP(兼容RabbitMQ),Kafka,和RocketMQ这三种微服务消息队列,对于我们今后在实际项目中落地提供了很大的帮助。

更多微服务消息队列可查看: node-mq-tutorial

使用场景多种多样:

  • 高并发:秒杀、抢票(FIFO)
  • 共享型:积分兑换(多子系统共用积分模块)
  • 通信型:服务端间消息传递(nodejs,java,python,go等等)
MQTT消息队列(物联网端与云间消息传递)

MQTT是一个物联网MQTT协议,主要解决的是物联网IoT网络情况复杂的问题。

阿里云有MQTT消息队列服务。通信协议支持MQTT,STOMP,GB-808等。数据传输层支持TCP长连接、SSL加密、Websocket等。

使用场景主要为数据传输:

  1. 车联网(远程控制,汽车数据上传)
  2. IM通讯(1对1单聊,1对多朋友圈)
  3. 视频直播(弹幕通知,聊天互动)
  4. 智能家居(电器数据上传,遥控指令)

目前我手上负责的运行了2年的聊天系统就是使用的这个服务,我们主要按照 设备serverPC 的方式, MQTT协议,Websocket传输协议 进行设备与PC间的数据通信。

MQTT关键名词解释

实例(Instance)

每个MQTT实例都对应一个全局唯一的服务接入点。

肉眼可见的区别就是在通过 mqtt.connect(url) 与server(broker)建立连接时,broker的url都是一致的。

假设有saleman1,salesman2···他们本地的前端与服务端间建立连接的url都是统一的,只是在clientId进行区分即可。

客户端Id(Client ID)

MQTT的Client ID是每个客户端的唯一标识,要求全局都是唯一的,使用同一个Client ID连接会被拒绝。

阿里云的ClientID由两部分组成 @@@ 。

通常情况下Group ID是多前端统一的,比如PC端,安卓移动端,ios移动端,DeviceID也是多前端统一的。

那么如何区分多端呢?可以对Client ID中间的@@@做修改。

比如:

let CID_PC = `@@@-PC`let CID_Android = `@@@-Android`let CID_IOS = `@@@-IOS`
组Id(Group ID)

用于指定一组逻辑功能完全一致的节点公用的组名,代表的是一类相同功能的设备。

Device ID

每个设备独一无二的标识。这个需要保证全局唯一,可以是每个传感器设备的序列号,可以是登录PC的userId。

父主题(Parent Topic)

MQTT协议基于Pub/Sub模型,任何消息都属于一个Topic。

Topic可以存在多级,第一级为父级Topic。

需要控制台单独创建。

子主题(Subtopic)

MQTT可以有二级Topic,也可以有三级Topic。

无需创建,代码中直接写即可。

P2P消息和Pub/Sub消息

Pub/Sub消息就是订阅和发布的模式,类似事件监听和广播。

如果对发布订阅不理解,可以去看Webhook到底是个啥?

MQTT除了支持Pub/Sub的模式,还支持P2P的模式。

什么是P2P消息?
  • P2P,全称为(Point to Point)。
  • 一对一的消息收发模式,只有一个消息发送者和一个消息接收者。
  • P2P模式下,消息发送者明确知道消息的预期接收者,并且这个消息只能被这个特定的 客户端消费
  • 发送者发送消息时,通过Topic指定接收者,接收者无需订阅即可获得该消息。
  • P2P 模式不仅降低注册订阅的成本,而且因为对链路有优化,所以降低推送延迟。
P2P模式和Pub/Sub模式的区别

发送消息时

  • Pub/Sub模式下,发送者需要按照与接受者约定好的Topic发送消息
  • P2P模式下,发送者无需按照Tpic发送,可以直接按照规范进行发送

接收消息时

  • Pub/Sub模式下,接收者需要提前订阅topic才能接消息
  • P2P模式下无需订阅即可接收消息
nodejs发送P2P消息
const p2pTopic =topic+"/p2p/GID_xxxx@@@DEVICEID_001";mqtt.client.publish(p2pTopic);

封装的mqtt.js通用class

  • 客户端连接 initClient(config)
  • 订阅topic subscribeTopic(topic, config)
  • 发送消息 publishMessage(message)
  • 接收消息 handleMessage(callback)
import mqtt from 'mqtt';import config from '@/config';export default class MQTT {  constructor(options) {    this.name = options.name;    this.connecting = false;  }  /**   * 客户端连接   */  initClient(config) {    const { url, groupId, key, password, topic: { publish: publishTopic }} = config;    return new Promise((resolve) => {      this.client = mqtt.connect(        {          url,          clientId: `${groupId}@@@${deviceId}`,          username: key,          password,        }      );      this.client.on('connect', () => {        this.connecting = true;        resolve(this);      });    });  }  /**   * 订阅topic   */  subscribeTopic(topic, config) {    if (this.connecting) {      this.client.subscribe(topic, config);    }    return this;  }  /**   * 发送消息   */  publishMessage(message) {    this.client.publish(publishTopic, message, { qos: 1 });  }  /**   * 接收消息   */  handleMessage(callback) {    if (!this.client._events.message) {      this.client.on('message', callback);    }  }}

客户端发包函数sendPacket

mqtt-packet生成一个可传输buffer
var mqtt = require('mqtt-packet')var object = {  cmd: 'publish',  retain: false,  qos: 0,  dup: false,  length: 10,  topic: 'test',  payload: 'test' // Can also be a Buffer}var opts = { protocolVersion: 4 } // default is 4. Usually, opts is a connect packetconsole.log(mqtt.generate(object))// Prints:  Which is the same as: new Buffer([//   48, 10, // Header (publish)//   0, 4, // Topic length//   116, 101, 115, 116, // Topic (test)//   116, 101, 115, 116 // Payload (test)// ])
sendPacket函数

发出packetsend事件并且通过mqtt.writeToStream将packet写入client的stream中。

var mqttPacket = require('mqtt-packet')function sendPacket (client, packet) {  client.emit('packetsend', packet)  mqttPacket.writeToStream(packet, client.stream, client.options)}
_sendPack方法
MqttClient.prototype._sendPacket = function (packet) {     sendPacket(this, packet);}

客户端连接 mqtt.connect()

mqtt client建立与mqtt server(broker)的连接,通常是通过给定一个'mqtt', 'mqtts', 'tcp', 'tls', 'ws', 'wss', 'wxs' , 'alis'为协议的url进行连接。

mqtt.connect([url], options)

官方说明:

  • 通过给定的url和配置连接到一个broker,并且返回一个Client。
  • url可以遵循以下协议:'mqtt', 'mqtts', 'tcp', 'tls', 'ws', 'wss', 'wxs' , 'alis'。( mqtt.js支持微信小程序和支付宝小程序,协议分别为wxs和alis。 )
  • url也可以是通过URL.parse()返回的对象。
  • 可以传入一个单对象,既包含url又包含选项。

再来看一下我手上项目的连接配置,连接结果。

敏感信息已通过foo,bar,baz或者xxxx的组合进行数据脱敏处理。

连接配置
{    key: 'xxxxxxxx',    secret: 'xxxxxxxx',    url: 'wss://foo-bar.mqtt.baz.com/mqtt',    groupId: 'FOO_BAR_BAZ_GID',    topic: {      publish: 'PUBLISH_TOPIC',      subscribe: ['PUBLISH_TOPIC/noticePC/', 'PUBLISH_TOPIC/p2p'],      unsubscribe: 'PUBLISH_TOPIC/noticeMobile/',    },}
  • key 账号
  • secret 密码
  • url 用于建立client与server(broker)mqtt连接的链接
  • groupId 组id
  • topic 发送消息的topic,订阅的topic,取消订阅的topic
连接结果

包括总览,响应头和请求头。

General
Request URL: wss://foo-bar.mqtt.baz.comRequest Method: GETStatus Code: 101 Switching Protocols
Response Header
HTTP/1.1 101 Switching Protocolsupgrade: websocketconnection: upgradesec-websocket-accept: xxxxxxxsec-websocket-protocol: mqtt
Request Header
GET wss://foo-bar.mqtt.baz.com/ HTTP/1.1Host: foo-bar.mqtt.baz.comConnection: UpgradePragma: no-cacheCache-Control: no-cacheUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36Upgrade: websocketOrigin: https://xxx.xxx.comSec-WebSocket-Version: 13Accept-Encoding: gzip, deflate, brAccept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,zh-TW;q=0.6Sec-WebSocket-Key: xxxxxxxxxSec-WebSocket-Extensions: permessage-deflate; client_max_window_bitsSec-WebSocket-Protocol: mqtt
源码分析

下面来看这段mqtt连接的代码。

this.client = mqtt.connect(  {    url,    clientId: `${groupId}@@@${deviceId}`,    username: key,    password,  });
function parseAuthOptions (opts) {  var matches  if (opts.auth) {    matches = opts.auth.match(/^(.+):(.+)$/)    if (matches) {      opts.username = matches[1]      opts.password = matches[2]    } else {      opts.username = opts.auth    }  }}/** * connect - connect to an MQTT broker. * * @param {String} [brokerUrl] - url of the broker, optional * @param {Object} opts - see MqttClient#constructor */function connect (brokerUrl, opts) {  if ((typeof brokerUrl === 'object') && !opts) {    //  可以传入一个单对象,既包含url又包含选项    opts = brokerUrl    brokerUrl = null  }  opts = opts || {}  // 设置username和password  parseAuthOptions(opts)  if (opts.query && typeof opts.query.clientId === 'string') {    // 设置Client Id    opts.clientId = opts.query.clientId  }  function wrapper (client) {   ...    return protocols[opts.protocol](client, opts)  }  // 最终返回一个mqtt client实例  return new MqttClient(wrapper, opts)}

订阅topic mqtt.Client#subscribe()

实际代码
const topic =  {      subscribe: ['PUBLISH_TOPIC/noticePC/', 'PUBLISH_TOPIC/p2p'],      unsubscribe: 'PUBLISH_TOPIC/noticeMobile/',};const config = { qos:1 };this.client.subscribe(topic.subscribe, config)
源码分析
MqttClient.prototype.subscribe = function () {  var packet  var args = new Array(arguments.length)  for (var i = 0; i < arguments.length; i++) {    args[i] = arguments[i]  }  var subs = []   // obj为订阅的topic列表  var obj = args.shift()  // qos等配置  var opts = args.pop()  var defaultOpts = {    qos: 0  }  opts = xtend(defaultOpts, opts)  // 数组类型的订阅的topic列表    if (Array.isArray(obj)) {    obj.forEach(function (topic) {      if (!that._resubscribeTopics.hasOwnProperty(topic) ||        that._resubscribeTopics[topic].qos < opts.qos ||          resubscribe) {        var currentOpts = {          topic: topic,          qos: opts.qos        }        // subs是最终的订阅的topic列表        subs.push(currentOpts)      }    })  }  // 这个packet很重要  packet = {    // 发出订阅命令    cmd: 'subscribe',    subscriptions: subs,    qos: 1,    retain: false,    dup: false,    messageId: this._nextId()  }  // 发出订阅包  this._sendPacket(packet)  return this}

发送消息 mqtt.Client#publish()

实际代码
const topic = {      publish: 'PUBLISH_TOPIC',};const messge = {   foo: '',   bar: '',   baz: '',   ...}const msgStr = JSON.stringify(message);this.client.publish(topic.publish, msgStr);

注意publish的消息需要使用JSON.stringify进行序列化,然后再发到指定的topic。

源码分析
MqttClient.prototype.publish = function (topic, message, opts, callback) {  var packet  var options = this.options  var defaultOpts = {qos: 0, retain: false, dup: false}  opts = xtend(defaultOpts, opts)  // 将消息传入packet的payload  packet = {    cmd: 'publish',    topic: topic,    payload: message,    qos: opts.qos,    retain: opts.retain,    messageId: this._nextId(),    dup: opts.dup  }  // 处理不同qos  switch (opts.qos) {    case 1:    case 2:       // 发出publish packet       this._sendPacketI(packet);        ...    default:       this._sendPacket(packet);        ...  }  return this}

接收消息 mqtt.Client “message”事件

实际代码
this.client.on('message', callback);

数据以callback的方式接收。

function (topic, message, packet) {}

topic代表接收到的topic,buffer则是具体的数据。

message是接收到的数据,谨记通过JSON.parse()对buffer做解析。

handleMessage(callback) {    this.client.on('message', callback);}this.client.handleMessage((topic, buffer) => {  let receiveMsg = null;  try {   receiveMsg = JSON.parse(buffer.toString());  } catch (e) {   receiveMsg = null;  }  if (!receiveMsg) {    return;  }  ...do something with receiveMsg...});
源码分析

MqttClient继承了EventEmitter。

从而进行可以使用on监听“message”事件。

inherits(MqttClient, EventEmitter)

那么到底是在哪里间发出message事件的呢?>emit the message event

  1. 基于websocket-stream建立websocket连接
  2. 使用pipe连接基于readable-stream.Writable创建的可写流
  3. nextTick调用_handlePacket
  4. 在handlePacket中调用handlePublish发出message事件
1.基于websocket-stream建立websocket连接
this.stream = this.streamBuilder(this)function streamBuilder (client, opts) {  return createWebSocket(client, opts)}var websocket = require('websocket-stream')function createWebSocket (client, opts) {  var websocketSubProtocol =    (opts.protocolId === 'MQIsdp') && (opts.protocolVersion === 3)      ? 'mqttv3.1'      : 'mqtt'  setDefaultOpts(opts)  var url = buildUrl(opts, client)  return websocket(url, [websocketSubProtocol], opts.wsOptions)}
2. 使用pipe连接基于readable-stream.Writable创建的可写流
var Writable = require('readable-stream').Writablevar writable = new Writable();this.stream.pipe(writable);
3.nextTick调用_handlePacket
writable._write = function (buf, enc, done) {    completeParse = done    parser.parse(buf)    work()}function work () {    var packet = packets.shift()    if (packet) {      that._handlePacket(packet, nextTickWork)    }}function nextTickWork () {    if (packets.length) {      process.nextTick(work)    } else {      var done = completeParse      completeParse = null      done()    }}
4. 在handlePacket中调用handlePublish发出message事件
MqttClient.prototype._handlePacket = function (packet, done) {  switch (packet.cmd) {    case 'publish':      this._handlePublish(packet, done)      break   ...}// emit the message eventMqttClient.prototype._handlePublish = function (packet, done) {  switch (qos) {    case 1: {      // emit the message event        if (!code) { that.emit('message', topic, message, packet) }    }}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

mqtt 发送消息过多_物联网宠儿mqtt.js那些事儿 的相关文章

  • nuxt打包后文件过大的优化

    在使用nuxt js来做项目的时候 遇到了加载缓慢的问题 解决思路如下 1 大文件拆分 2 文件压缩 大文件拆分 通过nuxt build analyze或者nuxt build a命令来启用 在package json中 添加 analy
  • TensorFlow Bug记录 CUBLAS_STATUS_NOT_INITIALIZED

    昨天刚装好也能运行的tensorflow突然之间报错 tensorflow stream executor cuda cuda blas cc 366 failed to create cublas handle CUBLAS STATUS
  • 虚拟服务器和vdi,VDI虚拟化平台搭建 01--VDI基本环境准备

    说明 此文章仅用于学习研究 不做任何商业用途 VDI 虚拟桌面基础架构 Virtual Desktop Infrastructure VDI基本软件硬件版本 服务器系统版本 exsi 6 7 vcenter版本 6 7 Vmware Hor
  • Typescript 基础类型 —— 布尔值 Boolean

    在JavaScript和TypeScript里布尔值都叫做boolean 表示逻辑值 true 和 false 关键字 boolean 实例 let isRes boolean false 编译结果 var isRes false 试图给
  • 【读懂Autosar代码】-1-概述

    点击返回 Autosar从入门到精通 实战篇 总目录 案例背景 共5页精讲 聊一聊这些封装中关键字宏的命名是如何构成的 FUNC FUNC P2CONST FUNC P2VAR P2VAR P2CONST CONSTP2VAR CONSTP
  • 论文期刊一般的审稿流程

    一 经常在网上看到某某人在问什么期刊的审稿周期 或者是投稿已多久怎么还没消息之类的帖子 作为经常帮国内外期刊审稿的人 对编辑部相对有所了解 因此特意发帖告知 供大家交流 论文审稿是个复杂的过程 并不是像大部分作者想象的那样送个一个专家看个几
  • String 判断字符串是否包含某个字符

    contains 判断 s 是否包含 ss 包含返回true 不包含返回false String s 你好 String ss 你 boolean ii s contains ss if ii true System out println
  • STM32调试特定函数出现Cannot access Memory

    MDK5出现Cannot access Memory 1 问题 2 原因 3 总结 1 问题 程序每次执行到了特定函数的位置时 keil里面全速运行 一直出现Cannot access Memory 再后面就是进入硬件错误中断了 执行到这个
  • C#使用COM+实现事务控制,操作多个数据库

    其中大部分内容参考自http blog itpub net 10752043 viewspace 991224 上面的是sqlserver的操作方式 因为我实际项目是用的oracle 就拿oracle试了一下 为了自己记录或者方便其他人 其
  • Linux下如何配置环境变量

    基础知识 首先 我们来了解一下什么是 环境变量 环境变量 通俗讲是操作系统或程序执行时候默认设定的参数 比如 PATH 路径变量 当要执行某个命令或程序的时候默认寻找的路径 然后 我们再来了解一下环境变量都有哪些类型 环境变量的分类 根据变
  • C++的类型

    C 的类型 按照标准 C 只有两种类型 基本类型和复合类型 但是里面细节多导致彻底理解它们有难度 所以这里只是简单总结一下 基本类型 基本类型分成算术类型和两种特殊的类型 算术类型 算术类型分成整数类型和浮点数类型两种 整数类型 以下都是整
  • 在springboot中使用Sse(Server-sent Events)Web实时通信技术-服务器发送事件SseEmitter

    最近在练习项目时需要用到消息实时推送技术 了解到有两种实时通信技术供我选择 SSE和WebSocket 详细了解后得知SSE是基于http协议 无需导入其他依赖 特点是服务端主动给客户端推送消息 单向 适合浏览器端只做数据接收 而webso
  • 华为OD机试真题-路灯照明问题-2023年OD统一考试(B卷)

    题目描述 在一条笔直的公路上安装了N个路灯 从位置0开始安装 路灯之间间距固定为100米 每个路灯都有自己的照明半径 请计算第一个路灯和最后一个路灯之间 无法照明的区间的长度和 输入描述 第一行为一个数N 表示路灯个数 1 lt N lt
  • Pysot训练自己的数据集

    数据集预处理操作 Pysot训练自己数据集前的预处理 Vesper0412的博客 CSDN博客 Pysot源码地址 https github com STVIR pysot 1 linux系统激活环境 conda activate pyto
  • 机器学习课程学习阶段总结

    机器学习课程学习阶段总结 线性回归 逻辑回归 逻辑回归 是一种分类算法 和之前的线性回归不是同一类问题 但是对于处理问题上有相同的思想 对于线性回归问题 有较容易理解的思路 首先指定一个形式确定的 h x Tx h theta x thet
  • 笔记本连接RK61键机械键盘非损坏的win和alt对调,数字键失灵以及特殊字母键失灵恢复

    1 问题描述 在打游戏或者码字的时候 无意中按下了键盘模式切换按键 导致了键盘的假性失灵状态 具体表现为 1 win和alt键功能对调 win按键无反应 alt键出现windows窗口 虽然不影响使用 但是很别扭 2 数字键失灵 键盘打不出
  • 网络安全有哪些经典笑话

    今天程序员同事发了一个链接给我 点开是一个调侃程序员有哪些经典笑话的帖子 给我看乐了 诸如 老婆给当程序员的老公打电话 下班顺路买一斤包子带回来 如果看到卖西瓜的 就买一个 当晚 程序员老公手捧一个包子进了家门 老婆怒道 你怎么就买了一个包
  • Android BLE 快速开发示例

    目录 概述 1 FastBle的使用 2 BLE开发实践方面的理解 3 FastBle源码解析 概述 思来想去 还是写这篇博文 记录一下 当时学习BLE的一些心得 重捡回当前Android知识 想深入了解蓝牙通讯知识 这个案例是非常不错的选
  • 毕业设计 - 基于单片机的测谎仪

    文章目录 1 简介 2 实现原理 3 主要器件 4 实现效果 正常情况 未说谎 异常情况 说谎了 5 部分实现代码 6 最后 1 简介 Hi 大家好 学长今天向大家介绍一个有趣的单片项目 基于单片机的测谎仪 大家可用于 课程设计 或 毕业设

随机推荐

  • 大数据技术(林子雨版)——期末复习知识点

    gt 大数据 云计算 大数据时代的三次信息化浪潮 时间 标志 解决的问题 代表企业 1980年前后 个人计算机 信息处理 Intel IBM 1995年前后 互联网 信息传输 谷歌 腾讯 2010年前后 大数据 云计算 物联网 信息爆炸 亚
  • Windows “Win+R“命令行运行常用命令

    Windows Win R 命令行运行常用命令 Windows操作系统提供了许多方便的方式来执行各种任务 其中之一是使用 Win R 运行命令行 这个快捷键组合可以让您迅速启动各种应用程序 工具和系统实用程序 而无需通过开始菜单或桌面快捷方
  • 【仲裁器】轮询仲裁round-robin,rr

    起因 在多主单从的设计中 当多个源端同时发起传输请求时 需要仲裁器根据优先级来判断响应哪一个源端 轮询仲裁 各个源端优先级相同 当其同时发起请求时 依次进行响应 电路图 代码 module rr arb input clk input rs
  • 区块链(二)-私有链的搭建

    私有链 搭建私有链 首先需要写一个创世块文件 创世块就是我自己链上的第一个区块 config nonce 0x0000000000000042 mixhash 0x00000000000000000000000000000000000000
  • 简单介绍Hyperledger fabric是什么

    Hyperledger Fabric作为超级账本的项目之一 目前基于它开发的区块链项目非常多 Linux基金会于2015年成立超级账本 以推进跨行业的区块链技术 相对于申报一个区块链标准 它鼓励通过社区合作的方式来发展区块链技术 带着知识产
  • 论git中使用https和ssh协议的区别

    论git中使用https和ssh协议的区别 SHELDON CUI S BLOG 2017 09 08 git https ssh 心得 http好还是ssh好 git可以使用四种主要的协议来传输资料 本地协议 Local HTTP 协议
  • TightVNC H264编解码(一)

    时光流逝 时间过的真快啊 疲于工作 发现近一个多月没写文章了 此文算是对最近的工作做个总结吧 经过尽二个月的不断摸索 TightVNC终于支持H264编解码了 前期真正编写H264编解码器只花了一周左右时间 但是测试发现效果并不是太理想 帧
  • 2022年android面试题,Android资深架构师分享学习经验及总结

    前言 最近有些朋友提问 Android QQ空间 换肤实现原理是什么 于是 我决定在这里做一下回答 对这个方面感兴趣的朋友也可以来看下 手q的换肤机制主要是通过拦截系统resource中的sPreloadedDrawables静态缓存变量
  • 为什么说“低估值买入,买到即赚到”?

    投资究竟能不能挣到钱 到底是由哪个环节决定的 买入还是卖出 直觉上说 这个问题的答案理所当然是 卖出 就连路边卖杂货的小商贩都明白 只要卖出价高于买入价 就可以挣到钱 直到我看了 穷查理宝典 接触到价值投资的理念 想法有了根本性改变 买入的
  • 对opencl helloworld代码的修正

    由于代码比较乱 数组也容易越界 故重新加了个类 用了stl vector 代码如下 test cl kernel void hello kernel global const float a global const float b glo
  • java jdbc线程池的使用

    好久没直接使用jdbc了 今天重温了一下相关知识 并对连接池的使用写了简单的示例 记录在此以便需要的同行参考和方便自己查阅 不足之处欢迎批评指正 1 dbcp数据源 所需jar包 dbcp 连接池的实现 commons pool2 连接池实
  • RedisTemplate 使用 Redis 缓存

    与使用注解方式不同 注解方式可以零配置 只需引入依赖并在启动类上加上 EnableCaching 注解就可以使用 而使用 RedisTemplate 方式麻烦些 需要做一些配置 Redis 配置 第一步还是引入依赖和在启动类上加上 Enab
  • 设计模式:策略模式

    我们玩游戏会有策略游戏 设计模式也会有策略模式 最开始接触策略模式的使用场景 是关于校验 针对不同的业务要进行不同的校验 同样的场景 优惠券折扣 不同渠道的信息发布等 Strategy Design Pattern 以下是GoF 是指提出和
  • 开发实况4.1.linux相关-CRT连接虚拟机提示用户名或密码错误

    文章目录 开发实况4 1 linux相关 CRT连接虚拟机提示用户名或密码错误 一 简介 二 问题解决 开发实况4 1 linux相关 CRT连接虚拟机提示用户名或密码错误 一 简介 已知我输入的用户名和密码正确但是却跳failed 二 问
  • Mac下使用GitHub+Hexo搭建个人博客

    首发链接 开始之前需要在电脑上安装好Git和node js Mac上可以使用Homebrew命令行工具来安装Git和node js 安装Homebrew 在命令行工具输入以下命令 如果已经安装过Homebrew可以忽略 usr bin ru
  • pjsip库使用时,顺序也有一定要求,

    LIBS PWD third lib pjsip lib libpjsua aarch64 unknown linux gnu a LIBS PWD third lib pjsip lib libpjsip ua aarch64 unkno
  • Arrays.asList(T...a)的使用问题

    我们经常会使用Arrays asList来初始化一个列表List 例如 List
  • 希尔排序图文详解+代码实现

    希尔排序也是一种插入排序 它是直接插入排序经过改进之后的一个更高效的版本 也称为缩小增量排序 性质 1 时间复杂度 O nlogn 2 空间复杂度 O 1 下面先介绍一下直接插入排序 理解了直接插入排序 希尔排序就很好理解了 实现代码也是由
  • 徐泽阳7.28黄金白银涨跌走势预测;期货原油实时策略指导

    黄金消息面与基本面解析 现货黄金反弹 因美元指数承压下行 但后者仍运行在92 50上方附近 在美联储政策会议召开之际 市场情绪趋于谨慎 美联储重点将围绕缩减购债以及对通胀飙升的忍耐度展开讨论 同时还要审慎考虑防疫形势可能的恶化 美元指数已从
  • mqtt 发送消息过多_物联网宠儿mqtt.js那些事儿

    常见的mq有Kafka RocketMQ和RabbitMQ 大家也很常见 前者很常见 MQTT是什么呢 MQTT属于IoT也就是物联网的概念 常见的mq有Kafka RocketMQ和RabbitMQ 大家也很常见 MQTT是什么呢 Kaf