前言

Mosquitto是一款轻量级的Mqtt消息代理软件,提供了C语言的动态库接口,用于运行C或C++编写的软件的场合,但是官方提供的默认编译版本是没有集成websockets功能的,如果需要Mosquitto代理软件能够支持websockets功能,则需要使用者自己去进行编译。本文即是介绍在Linux的环境下对Mosquitto软件和其C语言动态库如何进行编译的方法。

本文以CentOS 7.6环境为例进行说明,mosquitto采用2.0.9版本。

利用mosquitto的C语言客户端进行编程,通过cJSON或protobuff对消息内容进行格式化传输,并与前端JavaScript进行完全交互系列文章:

第一篇:Mosquitto打开Websockets模块并在Linux下的编译及安装使用

第二篇:cJSON模块在Mqtt代理mosquitto中的使用


一、Mosquitto使用命令

mosquitto [-c config file] [ -d | --daemon ] [-p port number] [-v]

-c 后面跟的是启动mosquitto可以调整的参数,比如是否开启基本认证,端口是什么,SSL单向和双向的认证配置等等。
-d 表示MQTT mosquitto将在后台运行。
-p 代表当前的mosquitto服务实例启动以后,其监听端口号,这个配置的覆盖[-c config file] 指定的配置文件中的端口
-v 代码调试模式(verbose)可以输出更多的信息

二、编译步骤

1.准备相关软件和库环境

要进行mosquitto的编译,需要提前准备好以下三个方面的动态库:

  • cmake3
    yum install -y cmake3.x86_64

  • openssl
    yum install -y openssl.x86_64 openssl-devel.x86_64 openssl-libs.x86_64 cmake3.x86_64

  • libwebsockets
    git clone https://codechina.csdn.net/mirrors/warmcat/libwebsockets.git

  • mosquitto
    git clone https://hub.fastgit.org/eclipse/mosquitto.git

2.编译libwebsockets

  • 启用支持libev
    因为LWS库默认状况下使用poll机制管理ws链接,为了让系统更高效的管理更多的并发,须要开启对libev的支持。可将libwebsockets 目录下CMakeLists.txt中的LWS_WITH_LIBEV选项由OFF改成ON来实现。然后进行编译:
cd libwebsockets/
mkdir build
cd build
cmake3 ..
make
make install

3.编译mossquitto

启用websockets,mosquitto需要开启websockets模块,需要更改以下两个地方的设置:

  • config.mk中设置WITH_WEBSOCKETS:=yes
  • src/CMakeLists.txt中的option(WITH_WEBSOCKETS “Include websockets support?” ON)
cd mosquitto-2.0.9/
mkdir build
cd build
cmake3 ..
make
make install

4.代码中如何使用

仅展示订阅端关键逻辑步骤代码。如果需要进行消息的发布需要使用消息发送函数mosquitto_publish。

#include <mosquitto.h>

bool session = true;
struct mosquitto *mosq = NULL;

void on_connect(struct mosquitto *mosq, void *obj, int reason_code)
{
	int rc;
	
	printf("##############on_connect: %s\n", mosquitto_connack_string(reason_code));
	if(reason_code != 0){		
		mosquitto_disconnect(mosq);
	}
	//订阅主题
	rc = mosquitto_subscribe(mosq, NULL, "test/control/#", 0);
	 printf("##################subscribing test/control/#..\n");
	if(rc != MOSQ_ERR_SUCCESS){
		fprintf(stderr, "Error subscribing: %s\n", mosquitto_strerror(rc));
		mosquitto_disconnect(mosq);
	}
}


void on_subscribe(struct mosquitto *mosq, void *obj, int mid, int qos_count, const int *granted_qos)
{
	int i;
	bool have_subscription = false;
	printf("###############on_subscribe: qos_count=%d \n", qos_count);
	for(i=0; i<qos_count; i++){
		printf("###########on_subscribe: %d:granted qos = %d\n", i, granted_qos[i]);
		if(granted_qos[i] <= 2){
			have_subscription = true;
		}
	}
	if(have_subscription == false){
		fprintf(stderr, "Error: All subscriptions rejected.\n");
		mosquitto_disconnect(mosq);
	}
}


void on_message(struct mosquitto *mosq, void *obj, const struct mosquitto_message *msg)
{
	
	if(msg->payloadlen){        
        //parse json here
        char * data=new char[msg->payloadlen+1];
		sprintf(data,(char *)msg->payload);
		printf("######## %s %d payload=%s data=%s \n", msg->topic, msg->qos, (char *)msg->payload,data);      
		
}

// 当断开连接时调用回调该函数
void on_disconnect(struct mosquitto *mosq, void *obj, int rc)
{
	printf("###############Call the function: my_disconnect_callback\n");
	//exitflag = TRUE;


}

void my_log_callback(struct mosquitto *mosq, void *userdata, int level, const char *str)
{
    printf("%s\n", str);
}

int main(int argc,char *argv[])
{
		//libmosquitto 库初始化
		mosquitto_lib_init();
		//创建mosquitto客户端
		mosq = mosquitto_new(NULL,session,NULL);
		if(!mosq){
		    printf("create client failed..\n");
		    mosquitto_lib_cleanup();
		    return 1;
		}
			
		mosquitto_log_callback_set(m_mosq, my_log_callback);
		mosquitto_connect_callback_set(m_mosq, on_connect);
		mosquitto_subscribe_callback_set(m_mosq, on_subscribe);
		mosquitto_message_callback_set(m_mosq, on_message);
		mosquitto_disconnect_callback_set(m_mosq, on_disconnect);
		
		//连接服务器
		if(mosquitto_connect_async(m_mosq, (char *)host_addra, port, keep_alive)!= MOSQ_ERR_SUCCESS){
		    fprintf(stderr, "Unable to connect.\n");
				mosquitto_destroy(m_mosq);
				mosquitto_lib_cleanup();
		    return 1;
		}
		//开启一个线程,在线程里不停的调用 mosquitto_loop() 来处理网络信息
		int loop = mosquitto_loop_start(m_mosq);
		if(loop != MOSQ_ERR_SUCCESS)
		{
		    printf("mosquitto loop error\n");
				mosquitto_destroy(m_mosq);
		    mosquitto_lib_cleanup();
		    return 1;
		}
		
		//销毁mosquitto环境
		mosquitto_destroy(mosq);
		mosquitto_lib_cleanup();
}

4.mosquitto运行配置

mosquitto如果需要启用websockets,则在配置文件中需要增加websockets监听端口,配置如下:

vi /usr/local/etc/mosquitto/mosquitto.conf
找到listeners节点,设置或修改如下(端口号可根据需要自定义):
listener 1883
protocol mqtt
listener 1884
protocol websockets

如果需要匿名登录进行消息的发送或接收,则设置如下:
allow_anonymous true

5.mosquitto运行

启动:

mosquitto -c /etc/mosquitto/mosquitto.conf -d -v

消息订阅和发布测试

//主题消息订阅
mosquitto_sub -t 'test/topic' -v
//主题消息发布
mosquitto_pub -t 'test/topic' -m 'hello world'

总结

本文仅仅介绍了mosquitto要启用websockets模块时,如何在Linux环境下进行源代码的编译的过程,以及如何进行配置的过程,其中代码部分展示了在利用mosquitto提供的动态库时编写Mqtt客户端的主要逻辑。

下一篇介绍后端C语言中利用cJSON库进行MQTT中JSON格式内容消息的接收和发送。

如果您对物联网相关方面技术感兴趣,可进群交流,QQ群:541826239

Logo

更多推荐