IoT gateway development: design process based on MQTT message bus (part 2)


Brother Tao's 022 original

I. Introduction

In the previous article, IoT Gateway Development: Based on the MQTT Message Bus Design Process (Part 1) , we talked about how to use the MQTT message bus in an IoT system gateway to implement multiple processes within the embedded system Intercommunication issues between.

The biggest advantages of this communication model are:

  1. Decoupling between modules;
  2. The modules can be developed in parallel;
  3. Hand over the TCP connection and sticky packet issues to the message bus, we only need to deal with the business layer;
  4. Easy to debug;

The above only describes the communication method between processes within an embedded system, so how does the gateway interact with the cloud platform ?

As mentioned in the previous article: The communication method between the gateway and the cloud platform is generally specified by the customer, and there are only a few (Alibaba Cloud, Huawei Cloud, Tencent Cloud, Amazon AWS platform). Generally, the gateway and the cloud platform are required to be in a long connection state, so that various commands from the cloud can be sent to the gateway at any time .

In this article, let's talk about this part of the content.

2. MQTT connection with cloud platform

Several current IoT cloud platforms all provide different access methods. For gateways, MQTT access is the most widely used .

We know that MQTT is just a protocol , which is implemented in different programming languages, and there are several implementations in C language.

Inside the gateway, a background deamon: MQTT Broker is running , which is actually the executable program mosquitto, which acts as a message bus. Please pay attention here: Because this message bus runs inside the embedded system , the clients that access the bus are those processes that need to communicate with each other . The number of these processes is limited, even for a more complex system, at most a dozen processes are almost the same. Therefore, the implementation of mosquitto can fully support the system load .

So, if you deploy an MQTT Broker in the cloud , in theory, you can directly use mosquitto as the message bus, but you have to evaluate the magnitude of the connected client (that is, the gateway), taking into account the concurrency Problem, stress test must be done.

With regard to back-end development, I don’t have much experience, and I dare not (and can’t) speak too much. It is guilty to mislead everyone. However, for general learning and testing, it is no problem to deploy mosquitto directly as a message bus in the cloud.

3. Proc_Bridge process: bridge between external and internal message bus

The following picture illustrates the role of the Proc_Bridge process in this model:

  1. Messages received from the cloud platform message bus need to be forwarded to the internal message bus;
  2. Messages received from the internal message bus need to be forwarded to the message bus of the cloud platform;

If it is implemented with mosquitto, how should it be implemented?

1. Mosquitto's API interface

The mosquitto implementation is based on a callback function mechanism, for example:

// 连接成功时的回调函数
void my_connect_callback(struct mosquitto *mosq, void *obj, int rc)
{
    // ...
}

// 连接失败时的回调函数
void my_disconnect_callback(struct mosquitto *mosq, void *obj, int result)
{
    // ...
}

// 接收到消息时的回调函数
void my_message_callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message)
{
	// ..
}

int main()
{
    // 其他代码
    // ...
    
    // 创建一个 mosquitto 对象
    struct mosquitto g_mosq = mosquitto_new("client_name", true, NULL);
    
    // 注册回调函数
    mosquitto_connect_callback_set(g_mosq, my_connect_callback);
	mosquitto_disconnect_callback_set(g_mosq, my_disconnect_callback);
	mosquitto_message_callback_set(g_mosq, my_message_callback);
	// 这里还有其他的回调函数设置
	
	// 开始连接到消息总线
	mosquitto_connect(g_mosq, "127.0.0.1", 1883, 60);
	
	while(1)
	{
		int rc = mosquitto_loop(g_mosq, -1, 1);
		if (rc) {
			printf("mqtt_portal: mosquitto_loop rc = %d \n", rc);
			sleep(1);
			mosquitto_reconnect(g_mosq);
		}
	}

	mosquitto_destroy(g_mosq);
	mosquitto_lib_cleanup();
	return 0;
}

The above code is the simplest code of a mosquitto client , using the callback function mechanism to make the development of the program very simple.

mosquitto helped us deal with the underlying details. As long as the registered function is called , it means that an event of interest has occurred .

This kind of callback mechanism is used in various open source software, such as: timer in glib, communication processing in libevent, data processing in libmodbus, driver development and timer in linux kernel , all of them are this routine. through!

Each process in the gateway only needs to add the above part of the code, and then it can be mounted on the message bus , so that it can send and receive data with other processes.

2. Use the UserData pointer to realize multiple MQTT connections

The above example is only connected to a message bus. For an ordinary process, the purpose of communication is achieved.

But for the Proc_Bridge process , the goal has not been achieved, because this process is in a bridge position and needs to be connected to the remote and local message buses at the same time . So how should it be achieved?

Take a look at the signature of the mosquitto_new function:

/*
 * obj - A user pointer that will be passed as an argument to any
 *      callbacks that are specified.
*/
libmosq_EXPORT struct mosquitto *mosquitto_new(const char *id, bool clean_session, void *obj);

The function of the last parameter is: you can set a user's own data (passed in as a pointer), then mosquitto will pass in this pointer when calling back any of our registered functions . Therefore, we can use this parameter to distinguish whether this connection is a remote connection? Or local connection.

Therefore, we can define a structure variable, record all the information of an MQTT connection here, and then register it with mosquitto. When mosquitto callback function pointer to this structure variables return to us, so you get all this data connection, in a way, this is also an object-oriented thinking.

// 从来表示一个 MQTT 连接的结构体
typedef struct{
	char *id;
	char *name;
	char *pw;
	char *host;
	int port;
	pthread_t tHandle;
	struct mosquitto *mosq;
	int mqtt_num;
}MQData;

The complete code has been placed in the network disk. In order to let you understand the principle first , I have posted the code in several key places here:

// 分配结构体变量
MQData userData = (MQData *)malloc(sizeof(MQData));

// 设置属于这里连接的参数: id, name 等等

// 创建 mosquitto 对象时,传入 userData。
struct mosquitto *mosq = mosquitto_new(userData->id, true, userData);

// 在回调函数中,把 obj 指针前转成 MQData 指针
static void messageCB(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message)
{
	MQData *userData = (MQData *)obj;
	
	// 此时就可以根据 userData 指针中的内容分辨出这是哪一个链接了
}

Another question: I wonder if you noticed the mosquitto_loop() function in the example? This function needs to be called continuously in the infinite while loop in order to start events inside mosuiqtto . (In fact, mosuiqtto also provided another simplified function mosquitto_loop_forever ).

That is to say: in each connection, it is necessary to continuously trigger the events of the bottom layer of mosquitto in order for the message system to send and receive smoothly. Therefore, in the sample code, two threads are used to connect to the bus of the cloud platform and the internal bus respectively.

Four, summary

After these two articles, I basically finished talking about the most basic communication model in the gateway of an IoT system , which is equivalent to the skeleton of a program, and the rest is to deal with the details of the business layer.

This is the first step in the Long March!

For a gateway, there are other more issues that need to be dealt with, such as: authentication of MQTT connection (user name + password, certificate), serialization and deserialization of communication data, encryption and decryption, etc., which will be slow in the future Slowly talk, I hope we go all the way!


[Original Statement]

Reprint: Welcome to reprint, but without the consent of the author, this statement must be retained, and the original link must be given in the article.


Don't brag, don't hype, don't exaggerate, write every article carefully!

Welcome to forward, to share to friends around technology, Columbia Road, to express my heartfelt thanks!

Recommended reading

My favorite way of communication between processes-message bus
C language pointer-from the underlying principles to fancy skills, with graphics and code to help you explain a thorough
step by step analysis-how to use C to implement object-oriented programming to
improve the code for a powerful tool : Macro definition-from getting started to abandoning
the underlying debugging principle of gdb is so simple.
Use setjmp and longjmp in C language to realize exception capture and coroutines
about encryption and certificates.
Deepen the LUA scripting language, so that you can fully understand the principle of debugging.

Guess you like

Origin blog.csdn.net/u012296253/article/details/114007309