mqtt的c语言实现的简单介绍

本篇文章给大家谈谈mqtt的c语言实现,以及对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。

本文目录一览:

1、如何在windows上用C语言实现MQTT协议2、C语言操作yaml配置文件通用操作工具3、MQTT简单介绍4、关于mosquitto怎么用c语言实现消息的订阅和发送(mqtt)5、「Android基于MQTT实现消息通知」

如何在windows上用C语言实现MQTT协议

C语言是一门通用计算机编程语言,广泛应用于底层开发。C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。

尽管C语言提供了许多低级处理的功能,但仍然保持着良好跨平台的特性,以一个标准规格写出的C语言程序可在许多电脑平台上进行编译,甚至包含一些嵌入式处理器(单片机或称MCU)以及超级电脑等作业平台。

二十世纪八十年代,为了避免各开发厂商用的C语言语法产生差异,由美国国家标准局为C语言制定了一套完整的美国国家标准语法,称为ANSI C,作为C语言最初的标准。 目前2011年12月8日,国际标准化组织(ISO)和国际电工委员会(IEC)发布的C11标准是C语言的第三个官方标准,也是C语言的最新标准,该标准更好的支持了汉字函数名和汉字标识符,一定程度上实现了汉字编程。

C语言是一门面向过程的计算机编程语言,与C++,Java等面向对象的编程语言有所不同。

其编译器主要有Clang、GCC、WIN-TC、SUBLIME、MSVC、Turbo C等。

mqtt的c语言实现的简单介绍

C语言操作yaml配置文件通用操作工具

在go语言中使用viper之类的库很方便的处理yaml配置文件,但是在c语言中就比较麻烦,经过一番思索和借助强大的github,发现了一个libyaml c库,但是网上的例子都比较麻烦,而且比较繁琐,就想法作了一个相对比较容易配置的解析应用,可以简单地类似viper 的模式进行配置实现不同的配置文件读取。如你的配置文件很复杂请按格式修改KeyValue 全局变量,欢迎大家一起完善

库请自行下载 GitHub – yaml/libyaml: Canonical source repository for LibYAML

直接上代码

yaml示例文件

%YAML 1.1

mqtt:

subtopic: “Control/#”

pubtopic: “bbt”

qos: 1

serveraddress: “tcp://192.168.0.25:1883”

clientid: “kvm_test”

writelog: false

writetodisk: false

outputfile: “./receivedMessages.txt”

hearttime: 30

#ifndef __CONFIG_H__

#define __CONFIG_H__

#ifdef __cplusplus

extern “C” {

#endif

/************************/

/* Minimum YAML version */

/************************/

#define YAML_VERSION_MAJOR 1

#define YAML_VERSION_MINOR 1

#define STRUCT_TYPE_NAME 100

#define INT_TYPE_NAME 101

#define STRING_TYPE_NAME 102

#define BOOL_TYPE_NAME 103

#define FLOAT_TYPE_NAME 104

#define MAP_TYPE_NAME 105

#define LIST_TYPE_NAME 106

typedef struct{

char *key;

void *value;

int valuetype;

char *parent;

}KeyValue,*pKeyValue;

#ifdef __cplusplus

}

#endif

#endif

#include

#include

#include

#include

#include

#include

#include

#include “config.h”

typedef struct {

char *SUBTOPIC; //string `yaml:”subtopic” mapstructure:”subtopic”` //”topic1″

char *PUBTOPIC; //string `yaml:”pubtopic” mapstructure:”pubtopic”`

int QOS; //byte `yaml:”qos” mapstructure:”qos”` //1

char *SERVERADDRESS; //string `yaml:”serveraddress” mapstructure:”serveraddress”` //= “tcp://mosquitto:1883”

char *CLIENTID; //string `yaml:”clientid” mapstructure:”clientid”` //= “mqtt_subscriber”

int HEARTTIME; //int `yaml:”hearttime” mapstructure:”hearttime”`

// CommandLocalPath string `yam:”commanlocalpath”`

}mqttSection,*pmqttSection;

typedef struct {

mqttSection Mqtt;// `yaml:”mqtt” mapstructure:”mqtt”`

// KVM kvmSection `yaml:”kvm” mapstructure:”kvm”`

}ConfigT;

ConfigT config;

static KeyValue webrtcconfig[]={

{“mqtt”,config,STRUCT_TYPE_NAME,NULL},

{“subtopic”,(config.Mqtt.SUBTOPIC),STRING_TYPE_NAME,”mqtt”},

{“pubtopic”,(config.Mqtt.PUBTOPIC),STRING_TYPE_NAME,”mqtt”},

{“qos”,(config.Mqtt.QOS),INT_TYPE_NAME,”mqtt”},

{“serveraddress”,(config.Mqtt.SERVERADDRESS),STRING_TYPE_NAME,”mqtt”},

{“clientid”,(config.Mqtt.CLIENTID),STRING_TYPE_NAME,”mqtt”},

{“hearttime”,(config.Mqtt.HEARTTIME),INT_TYPE_NAME,”mqtt”},

{NULL,NULL,0,NULL},

};

int printConfig(ConfigT * pconfig){

if(pconfig==NULL) return -1;

printf(“mqtt:r “);

if(pconfig-Mqtt.SUBTOPIC!=NULL) {printf(“subtopic: %sr “,pconfig-Mqtt.SUBTOPIC); }

if(pconfig-Mqtt.SUBTOPIC!=NULL) {printf(“pubtopic: %sr “,pconfig-Mqtt.PUBTOPIC); }

printf(“qos: %dr “,config.Mqtt.QOS);

if(pconfig-Mqtt.SERVERADDRESS!=NULL) {printf(“serveraddress: %sr “,pconfig-Mqtt.SERVERADDRESS); }

if(pconfig-Mqtt.CLIENTID!=NULL) {printf(“clientid: %sr “,pconfig-Mqtt.CLIENTID); }

printf(“hearttime: %dr “,config.Mqtt.HEARTTIME);

}

int freeConfig(ConfigT * pconfig){

if(pconfig==NULL) return -1;

if(pconfig-Mqtt.SERVERADDRESS!=NULL) {free(pconfig-Mqtt.SERVERADDRESS); }

if(pconfig-Mqtt.CLIENTID!=NULL) {free(pconfig-Mqtt.CLIENTID); }

if(pconfig-Mqtt.SUBTOPIC!=NULL) {free(pconfig-Mqtt.SUBTOPIC); }

}

char currentkey[100];

void getvalue(yaml_event_t event,pKeyValue *ppconfigs){

char *value = (char *)event.data.scalar.value;

pKeyValue pconfig=*ppconfigs;

char *pstringname;

while(pconfig-key!=NULL){

if(currentkey[0]!=0){

if(!strcmp(currentkey,pconfig-key))

{

switch(pconfig-valuetype){

case STRING_TYPE_NAME:

pstringname=strdup(value);

printf(“get string value %sr “,pstringname);

*((char**)pconfig-value)=pstringname;

memset(currentkey, 0, sizeof(currentkey));

break;

case INT_TYPE_NAME:

*((int*)(pconfig-value))=atoi(value);

memset(currentkey, 0, sizeof(currentkey));

break;

case BOOL_TYPE_NAME:

if(!strcmp(value,”true”)) *((bool*)(pconfig-value))=true;

else *((bool*)(pconfig-value))=false;

memset(currentkey, 0, sizeof(currentkey));

break;

case FLOAT_TYPE_NAME:

*((float*)(pconfig-value))=atof(value);

memset(currentkey, 0, sizeof(currentkey));

break;

case STRUCT_TYPE_NAME:

case MAP_TYPE_NAME:

case LIST_TYPE_NAME:

memset(currentkey, 0, sizeof(currentkey));

strncpy(currentkey,value,strlen(value));

break;

default:

break;

}

break;

}

//continue;

}else{

if(!strcmp(value,pconfig-key)){

strncpy(currentkey,pconfig-key,strlen(pconfig-key));

break;

}

}

pconfig++;

}

}

int Load_YAML_Config( char *yaml_file, KeyValue *(configs[]) )

{

struct stat filecheck;

yaml_parser_t parser;

yaml_event_t event;

bool done = 0;

unsigned char type = 0;

unsigned char sub_type = 0;

if (stat(yaml_file, filecheck) != false )

{

printf(“[%s, line %d] Cannot open configuration file ‘%s’! %s”, __FILE__, __LINE__, yaml_file, strerror(errno) );

return -1;

}

FILE *fh = fopen(yaml_file, “r”);

if (!yaml_parser_initialize(parser))

{

printf(“[%s, line %d] Failed to initialize the libyaml parser. Abort!”, __FILE__, __LINE__);

return -1;

}

if (fh == NULL)

{

printf(“[%s, line %d] Failed to open the configuration file ‘%s’ Abort!”, __FILE__, __LINE__, yaml_file);

return -1;

}

memset(currentkey, 0, sizeof(currentkey));

/* Set input file */

yaml_parser_set_input_file(parser, fh);

while(!done)

{

if (!yaml_parser_parse(parser, event))

{

/* Useful YAML vars: parser.context_mark.line+1, parser.context_mark.column+1, parser.problem, parser.problem_mark.line+1, parser.problem_mark.column+1 */

printf( “[%s, line %d] libyam parse error at line %ld in ‘%s'”, __FILE__, __LINE__, parser.problem_mark.line+1, yaml_file);

}

if ( event.type == YAML_DOCUMENT_START_EVENT )

{

//yaml file first line is version

//%YAML 1.1

//—

yaml_version_directive_t *ver = event.data.document_start.version_directive;

if ( ver == NULL )

{

printf( “[%s, line %d] Invalid configuration file. Configuration must start with “%%YAML 1.1″”, __FILE__, __LINE__);

}

int major = ver-major;

int minor = ver-minor;

if (! (major == YAML_VERSION_MAJOR minor == YAML_VERSION_MINOR) )

{

printf( “[%s, line %d] Configuration has a invalid YAML version. Must be 1.1 or above”, __FILE__, __LINE__);

return -1;

}

}

else if ( event.type == YAML_STREAM_END_EVENT )

{

done = true;

}

else if ( event.type == YAML_MAPPING_END_EVENT )

{

sub_type = 0;

}

else if ( event.type == YAML_SCALAR_EVENT )

{

getvalue(event,configs);

}

}

return 0;

}

int main(int argc, char *argv[]){

pKeyValue pconfig=webrtcconfig[0];

Load_YAML_Config(“../../etc/kvmagent.yml”,pconfig);

printConfig(config);

freeConfig(config);

}

MQTT简单介绍

MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅模式的”轻量级”通讯协议,该协议构建于TCP/IP协议上。好比你给好友发送一封电子邮件,发送完成后你可以去做别的事情,收件人也不必立刻响应,可以在自己有空的时候查看邮件,是一个典型的异步发布/订阅场景。而另一种典型的同步请求/回答场景,可以用接打电话的场景来类比。

MQTT的设计遵循以下的原则:

为了满足不同的场景,MQTT支持三种不同级别的服务质量(Quality of Service,QoS)为不同场景提供消息可靠性:

MQTT拥有14种不同的消息类型:

实现MQTT协议需要客户端和服务器端通讯完成,在通讯过程中,MQTT协议中有三种身份:发布者(Publish)、代理(Broker)(服务器)、订阅者(Subscribe)。其中,消息的发布者和订阅者都是客户端,消息代理是服务器,消息发布者可以同时是订阅者。

MQTT传输的消息分为:主题(Topic)和负载(payload)两部分:

MQTT会构建底层网络传输:它将建立客户端到服务器的连接,提供两者之间的一个有序的、无损的、基于字节流的双向传输。

当应用数据通过MQTT网络发送时,MQTT会把与之相关的服务质量(QoS)和主题名(Topic)相关连。

一个使用MQTT协议的应用程序或者设备,它总是建立到服务器的网络连接。客户端可以:

MQTT服务器以称为”消息代理”(Broker),可以是一个应用程序或一台设备。它是位于消息发布者和订阅者之间,它可以:

订阅包含主题筛选器(Topic Filter)和最大服务质量(QoS)。订阅会与一个会话(Session)关联。一个会话可以包含多个订阅。每一个会话中的每个订阅都有一个不同的主题筛选器。

每个客户端与服务器建立连接后就是一个会话,客户端和服务器之间有状态交互。会话存在于一个网络之间,也可能在客户端和服务器之间跨越多个连续的网络连接。

连接到一个应用程序消息的标签,该标签与服务器的订阅相匹配。服务器会将消息发送给订阅所匹配标签的每个客户端。

一个对主题名通配符筛选器,在订阅表达式中使用,表示订阅所匹配到的多个主题。

消息订阅者所具体接收的内容。

MQTT协议中定义了一些方法(也被称为动作),来于表示对确定资源所进行操作。这个资源可以代表预先存在的数据或动态生成数据,这取决于服务器的实现。通常来说,资源指服务器上的文件或输出。主要方法有:

关于mosquitto怎么用c语言实现消息的订阅和发送(mqtt)

1.目标:测试Mosquitto使用MQTT协议发消息的相关性能指标,包含发送速度,并发负载能力,资源占用,消息到达率。

2.MQTT协议简介:

1).建立长连接。客户端发起请求和服务端建立长连接,建立成功后,服务端会返回ACK(CONNACK)

2).客户端订阅:客户端发起订阅,订阅成功后,服务端会返回ACK(SUBACK)

3).发消息:发布者会给服务端发消息,服务端在把消息给合适的客户端。

Qos=0(服务质量):客户端消息收到后,不会发出ACK给服务端(PUBACK)。

 Qos =1:服务端会发ACK给发布者,客户端收到消息后会发ACK给服务端。

4).取消订阅:客户端发起取消订阅,服务端返回ACK(UNSUBACK)

5)PingreqPingresp:客户端和服务端会保持心跳。

3.存在问题:

1. 如何模拟出40W的用户

2. 如何长连接,订阅,发消息,取消订阅,Pingreq行为如何实现。

4. python开源库 Mosquitto.py,解决所有问题

1. 模拟40W用户

a)可以使用虚拟机和Mosquitto.py实现,具体为:一般一台虚拟机最多是6W+的模拟数据(需要修改句柄数,我使用5W),方法是Client_id可以简单的做出5W个来,然后调用Mosquitto里面的connect方法,建立长连接。准备8台虚拟机就可以实现40W客户端的模拟

2.行为的模拟

a)订阅:Mosquitto.subscribe / 发消息:Mosquitto.publish / 取消订阅:Mosquitto.unsubscribe。 简单一句话 Mosquitto库实现所有的行为.

5. 指标:发送速度,到达率,并发负载,资源占用。

a. 发送速度:服务端日志记录,分析解决

b. 到达率: 1.客户端记录下收到消息,分析计算。2.计算服务端收到的PUBACK(客户端收到消息返回的ACK),进行计算

c. 并发负载:5W 用户不断增加,注意观察服务端的负载情况。

e.资源占用:其实主要是cpu/mem/带宽:cpu多核的话需要观察top命令下的_id字段, mem可以观察free -h命令的剩余mem, 带宽可以使用mpstat进行观察

6. 可以遇见问题:

a. 模拟客户端的虚拟机需要修改句柄数才能支持5W的客户端模拟数量

b. 要先吃透MQTT协议的流程,吃透了进行测试会非常的方便

c. Clear session,设置为true则不为客户端保留休息,设置为false保留消息。其实就是客户端离线后在连接上可以收到之前推出的消息。

「Android基于MQTT实现消息通知」

在对接项目中 IoT 时,发现目前有对 MQTT 做了接入,这里记录一下,官方的资料比较详细,这里主要从实现细节出发;对具体的需求以及配套的技术方案进行整理,以供参考。

提到 IoT(Internet of Things)、IIoT(Industrial IoT ) 不得不说 MQTT ,其被广泛的应用在物联网以及工业物联网之中,是一种消息传递协议。不同于我们所认识的平时常见的一些智能设备,如手机、电脑、平板等;这些设备一般都有着很好的计算能力,所依赖的网络环境很优质。但是一般的硬件设备性能较差,网络环境不稳定,而 MQTT 则是专门针对于硬件性能,网络状态不稳定场景下而生的。有着天然的优势。

详细信息

主要需要注意 Topics 的匹配规则,分为单项通配符,与多项通配符。单项以 + 连接:this/is/+/single,其中仅仅 + 部分可以被替换为单个路径(以 / 分割)。多项通配符仅支持在尾端支持:this/is/multi/#,并且是多级的。

详细信息

保活时效,包括其他的字段,官方文档都给出了很详细的解释,认真了解一项技术实现,官方的文档还是最好的选择文档。这里主要基本认识MQTT是个什么东西,具体的实现细节与规范也不是一两句话可以说的清楚的,且可能存在误导的风险。MQTT

以实际的项目为例,现需要实现的功能有:

功能相对很简单,总结就是服务端推送消息,设备根据消息做出响应。

导入依赖

主要分为几个类:a.主体请求 Client ,b.数据返回的回调 dataCallback ,c.链接状态回调 connectCallback ,d.具体消息处理策略 IHandler 。方案主要就包括这几个大类,逐步实现各个细节。

在实现之前,列举几个关键的参数,参数配置在 MqttConnectOptions 中

关于自动重新连接有三个必要条件, cleanSession 需要设置为 false , isAutomaticReconnect 需要设置为 true ,并且初始 已经连接过 。划重点,这里就要求, MQTT 虽然可以自动重试连接当时必须有这三个前提,那么首次由于网络等其他原因,这里的重试机制是需要我们自身去实现的,也就是需要保证首次能够连接到服务端。源码以及注释:

需要注意的是这里的 ClientId ,是唯一性的,像 IoT 设备以设备 deviceId 作为 ClientId ,如果换成用户 userId ,当在多设备登录的情况下,那么重试等其他一些机制会影响预期结果,给排查问题带来一定的难度。

消息体中会包含不同的 type ,根据不同的 type 实现不同的处理器,当然为了灵活还要借助 注解机制 。

通过反射的方式加载对应的 IHandler 实现类,核心代码

使用时,直接加上注解:

整个流程的主要部分已经给出,核心是通过不同的消息 type 查找出对应的 处理器 ;当然这部分主要是由注解完成的,对于处理器的查找则是通过 反射 的方式来进行匹配的。

MQTT官网

关于mqtt的c语言实现和的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。

本文来自投稿,不代表【】观点,发布者:【

本文地址: ,如若转载,请注明出处!

举报投诉邮箱:253000106@qq.com

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2024年3月31日 08:25:06
下一篇 2024年3月31日 08:29:10

相关推荐

  • c语言改写模式,c语言实现修改功能

    c语言程序修改? 1、这个程序有4个错误,我都加粗了,第一个是m没有赋初值,第二个是while表达式中的ch=getchar()需要括号括起来,第三个是m=m*10+ch-0中的0也需要用单引号括起来,第四个是第2个while中为m!=0。 2、define容易造成误会,因为不符合一般的编程习惯,false 0, true 1;scanf放在你的那个地方是达…

    2024年5月23日
    3900
  • c语言控制代码的换码序列,c语言交换代码

    求C语言编程大神解答一下下面这个编程代码? k==5,用5去除125余0,所以r=125%5中r为0。由于!0为1,所以执行while循环体:先打印出5(k的值),再n=n/k==125/5=25;由于251则再打印出*号。这一循环结果输出是5*。 下面是我的代码,三个函数分别对应三个问题。 在实现基本要求的前提下,拓展了可以从键盘输入的功能,以下为各题代码…

    2024年5月23日
    5600
  • c语言扫描io脚状态,c语言端口扫描

    求51单片机的上升沿和下降沿C语言检测程序列子,端口就是普通IO口。 上升沿触发是当信号有上升沿时的开关动作,当电位由低变高而触发输出变化的就叫上升沿触发。也就是当测到的信号电位是从低到高也就是上升时就触发,叫做上升沿触发。 单片机怎么计算1s内下降沿的个数的C语言程序或者计算两个下降沿的时间(检测脉冲频率)计算1s内下降沿的个数方法是,一个定时器设置定时1…

    2024年5月23日
    4400
  • c语言mallloc使用的简单介绍

    C语言中使用malloc必须加#includemallo.h? 1、在C语言中使用malloc函数进行动态内存分配。malloc的全称是memory allocation,中文叫动态内存分配。原型:extern void malloc(unsigned int num_bytes);功能:分配长度为num_bytes字节的内存块。 2、你可以看一下C语言那本…

    2024年5月23日
    4400
  • c语言三位小数,C语言三位小数

    怎样用C++语言输出精确到小数点后三位的数? 1、用C++语言输出精确到小数点后三位的数,可以参考下面给出的代码:coutsetiosflags(ios:fixed)setprecision(3)。其中 setiosflags中set是设置的意思。ios是iostream的缩写,即输入输出流。flags是标志的意思。 2、要精确到小数点后若干位,则数据类型为…

    2024年5月23日
    7200
  • c语言21点游戏,二十一点游戏代码c语言

    如何使用C语言编写简单小游戏? 1、数学知识:长方形的面积S=a*b 长方形周长L=2*(a+b)其中a b分别为长方形的宽和高。算法分析:长方形面积及周长均依赖于宽和高,所以先要输入宽高值,然后根据公式计算,输出结果即可。 2、/*也不知道你是什么级别的,我是一个新手,刚接触编程语言,以下是我自己变得一个小程序,在所有c语言的编译器(vc++0、turbo…

    2024年5月23日
    6300
  • javascriptcanvas的简单介绍

    如何使用js在画布上绘制图形 1、可以使用 drawImage()方法把一幅图像绘制到画布上。 以使用三种不同的参数组合。最简单的调用方式是传入一个 HTML 元素,以及绘制该图像的起点的 x 和 y 坐标。 2、效果图:使用JavaScript在画布中绘制文本图形首先我们来看看要在画布上绘制文本图形,需要用到的最重要的属性和方法:font属性:定义文本的字…

    2024年5月23日
    4200
  • cortexm4linux的简单介绍

    Cortex-M4的主要功能 Cortex-M4提供了无可比拟的功能,以将[1] 32位控制与领先的数字信号处理技术集成来满足需要很高能效级别的市场。 Cortex-M4核心具有浮点单元(FPU)单精度,支持所有Arm单精度数据处理指令和数据类型。它还实现了一套完整的DSP指令和一个提高应用程序安全性的内存保护单元(MPU)。 主要是m4比m3多了dsp的支…

    2024年5月23日
    4300
  • c语言当中的null,C语言当中的符号

    C/C++中,NULL和null的区别是什么? nul 和 null要看编译器,不同的编译器有所区别。 所以C或者C++中都使用一个特殊定义NULL表示无效值,其本质就是未定义具体数据类型的0值。 null是是什么都没有的意思。在java中表示空对象。 本意是“空的;元素只有零的”意思。计算机中通常表示空值,无结果,或是空集合。\x0d\x0a在ASCII码…

    2024年5月23日
    4500
  • 3desjavaphp的简单介绍

    php的3des加密结果与java不一致 他们的加密算法都是通用的,是可以解开的,只要你des的模式,加密长度,初始向量什么的都一样就可以。 JAVA写RSA加密,私钥都是一样的,公钥每次加密的结果不一样跟对数据的padding(填充)有关。Padding(填充)属性定义元素边框与元素内容之间的空间。padding简写属性在一个声明中设置所有内边距属性。 要…

    2024年5月23日
    4700

发表回复

登录后才能评论



关注微信