在Eclipse Paho MQTT网站上,开发人员提供了一个客户端示例(http://www.eclipse.org/paho/files/mqttdoc/MQTTClient/html/pubsync.html),它执行以下操作:
如果你想要的只是发布一条消息,这很有效。
在我的代码中,我有一个函数包含与上述示例中几乎相同的代码,但是,从main()重复调用该函数,因为我需要一个接一个地发布大量消息。问题是,如果我使用与示例中完全相同的代码,每次调用我的函数时,都会创建一个新连接,并在销毁后不久。只要重复调用该函数,就会一次又一次地发生这种情况,从而导致巨大的开销。
有没有办法检查是否已经创建了一个客户端对象,如果是,那么不要再次使用现有的对象?
根据我的理解,MQTTClient_isConnected()函数应该这样做:https://www.eclipse.org/paho/files/mqttdoc/MQTTClient/html/_m_q_t_t_client_8h.html#ad9e40bdb7149ee3e5d075db7f51a735f 但如果我这样尝试,我会遇到分段错误:
if (!MQTTClient_isConnected(client)) {
MQTTClient_create(&client, mqtt.addr, CLIENT_ID, MQTTCLIENT_PERSISTENCE_NONE, NULL);
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;
conn_opts.username = TOKEN;
if (MQTTClient_connect(client, &conn_opts) != MQTTCLIENT_SUCCESS) {
printf("\n==> Connection to MQTT Broker failed.\n");
MQTTClient_destroy(&client);
exit(EXIT_FAILURE);
}
}
[编辑]
这是一个简单的演示代码,可以更好地说明我要完成的任务:
#include <stdio.h>
#include <MQTTClient.h>
MQTTClient client;
void publish_MQTT() {
MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
MQTTClient_message pubmsg = MQTTClient_message_initializer;
MQTTClient_deliveryToken token;
char *payload = (char *)calloc(1024, sizeof(char));
strcpy(payload, "hello");
printf("DEBUG_BEFORE >> MQTTClient_isConnected(client) = %d\n", MQTTClient_isConnected(client)); // DEBUG OUTPUT
if (!MQTTClient_isConnected(client)) {
MQTTClient_create(&client, addr, CLIENT_ID, MQTTCLIENT_PERSISTENCE_NONE, NULL);
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;
conn_opts.username = TOKEN;
if (MQTTClient_connect(client, &conn_opts) != MQTTCLIENT_SUCCESS) {
fprintf(stderr, RED "\n==> Connection to MQTT Broker failed.\n" RESET_CL);
MQTTClient_destroy(&client);
free(payload);
exit(EXIT_FAILURE);
}
}
printf("DEBUG_AFTER >> MQTTClient_isConnected(client) = %d\n", MQTTClient_isConnected(client)); // DEBUG OUTPUT
pubmsg.payload = payload;
pubmsg.payloadlen = strlen(payload);
pubmsg.qos = QOS;
pubmsg.retained = 0;
MQTTClient_publishMessage(client, TOPIC, &pubmsg, &token);
MQTTClient_waitForCompletion(client, token, TIMEOUT);
//MQTTClient_disconnect(client, 10000);
//MQTTClient_destroy(&client);
free(payload);
}
int main(void) {
for (i=0; i<1000; i++) {
publish_MQTT();
}
return 0;
}
请忽略这样一个事实,即从未指定addr参数(在我的实际代码中)或者在publish_MQTT()函数中指定消息是非常无用的(在我的实际代码中,数据是从main()传递的该功能)。
答案 0 :(得分:1)
我明白了:显然,原始帖子中的示例代码完全没有问题。
事实证明我是一次又一次地将MQTT服务器的端口附加到addr参数(在此处未显示的代码部分,因为我没有怀疑错误的来源在那里),每次调用了publish_MQTT()函数。这使得addr char字符串增长并最终超过指定的长度,从而导致SegFault。
这样一切都按预期工作:
printf("\nADDR = %s\n\n", addr); // DEBUG OUTPUT
if (!MQTTClient_isConnected(client)) {
strcat(strcat(addr, ":"), pt); // This line needed to be placed here, not before that if block
MQTTClient_create(&client, addr, CLIENT_ID, MQTTCLIENT_PERSISTENCE_NONE, NULL);
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;
conn_opts.username = TOKEN;
if (MQTTClient_connect(client, &conn_opts) != MQTTCLIENT_SUCCESS) {
printf("\n==> Connection to MQTT Broker failed.\n");
MQTTClient_destroy(&client);
free(payload);
exit(EXIT_FAILURE);
}
}
答案 1 :(得分:0)
可能你正在设置“清洁会议标志”,这是什么意思:“ 如果ClientId表示已连接到服务器的客户端,那么服务器必须断开现有客户端[MQTT-3.1.4-2]。“(来自mqtt标准)。所以客户端断开连接(现有客户端)。
示例中的代码似乎是可重用的。看起来传递函数参数有问题。例如,如果函数需要地址,并且您自己提供对象。
标准化: “3.2.2.2会议现场 位置:Connect Acknowledge Flags的第0位。
如果服务器接受CleanSession设置为1的连接,除了在CONNACK数据包[MQTT-3.2.2-1]中设置零返回码之外,服务器必须在CONNACK数据包中将Session Present设置为0。 / p>
如果服务器接受将CleanSession设置为0的连接,则Session Present中设置的值取决于Server是否已为所提供的客户端ID存储了Session状态。如果服务器已存储会话状态,则它必须在CONNACK数据包[MQTT-3.2.2-2]中将Session Present设置为1。如果服务器没有存储的会话状态,它必须在CONNACK数据包中将Session Present设置为0。这是在CONNACK数据包“。
中设置零返回码的补充