mqtt:避免缓冲消息

Posted

技术标签:

【中文标题】mqtt:避免缓冲消息【英文标题】:mqtt: avoid buffering of messages 【发布时间】:2018-04-14 15:23:31 【问题描述】:

现在我正在处理一个项目,其中 python 脚本订阅代理上的主题并等待消息。收到消息后,脚本会执行一些操作并显示图像约 5 秒。至此,一切正常。

我正在努力解决的问题是,当函数已经执行时收到消息时,函数在完成后会直接再次执行。例如:3条消息一个接一个直接发布,函数一个接一个被调用,显示3倍的图片。

我想要实现的行为是忽略在函数已经执行时发布的消息。

此链接 (http://www.steves-internet-guide.com/loop-python-mqtt-client/) 表示:

当新消息到达 Python MQTT 客户端时,它们被放置在 接收缓冲区。

消息位于此接收缓冲区中,等待被 客户端程序。

我认为这就是问题所在!但我不明白如何避免这种缓冲行为。

就像建议的那样,我尝试设置标志等,但这不起作用。

为了更好地理解我写了一个简单的脚本,当消息发布时打印1, 2, 3, 4, 5

#!/usr/bin/env python

import os, os.path
import time
import subprocess
import paho.mqtt.client as mqtt

mqtt_username = "user"
mqtt_password = "password"
mqtt_topic = "Topic"

def on_connect(client, userdata, flags, rc):
    client.subscribe(mqtt_topic)

def on_message(client, userdata, msg):
    print('1')
    time.sleep(1)
    print('2')
    time.sleep(1)
    print('3')
    time.sleep(1)
    print('4')
    time.sleep(1)
    print('5')
    time.sleep(1)
    print('---')

client = mqtt.Client()

client.on_connect = on_connect
client.on_message = on_message

client.username_pw_set(mqtt_username, mqtt_password)
client.connect("localhost", 1883, 60)
client.loop_forever()

使用此命令发布消息:

mosquitto_pub -d -u user -P password -t Topic -m "Hello"

发布一条消息一切都很好。一个接一个地直接发布三条消息会产生这样的输出:

1
2
3
4
5
---
1
2
3
4
5
---
1
2
3
4
5
---

但它应该会导致这个输出,忽略其他两条消息:

1
2
3
4
5
---

【问题讨论】:

该函数可以返回一个全局保存的时间戳。然后你可以在函数的第一行检查那个时间戳,如果系统时间和那个时间戳之间的差异太小,就立即返回。 看起来像是重新进入标志和超时的组合。您在第一次进入时设置标志并显示图像,如果设置了标志,则不进入,但您检查超时以重置标志。您可以使用闭包来保持本地标志和超时状态。 【参考方案1】:

你可以有一个全局布尔变量functionCalled来保存函数是否被调用,另一个变量t来保存time.time()来记录函数被调用的时间。根据您的描述,也许您不需要变量来保持时间,但以防万一。

if functionCalled:
    functionCalled = false
    if Time.time() - t < 5 seconds:
        # DontShowImage
else:
    functionCalled = true
    t = time.time()
    # show image`

【讨论】:

问题是消息被缓冲了,函数在完成后被再次调用。所以设置标志不起作用。我用更多细节改进了这个问题【参考方案2】:

该函数可以返回一个全局保存的时间戳。然后你可以在函数的第一行检查那个时间戳并立即返回,如果系统时间和那个时间戳之间的差异太小:

from datetime import datetime

lastMessage = 0

def on_message(client, userdata, msg):
    if datetime.now().timestamp() - globals()['lastMessage'] > 5 # sec:
        //this function shows an image for about 5 seconds
        globals()['lastMessage'] = datetime.now().timestamp()

【讨论】:

这里也一样。设置标志对我不起作用。问题是消息被缓冲了。我用更多细节改进了这个问题 更新了我的答案。抱歉,我忘记了重要的部分:更新 lastMessage 的值。

以上是关于mqtt:避免缓冲消息的主要内容,如果未能解决你的问题,请参考以下文章

ALSA 音序器:使用高速 MIDI 避免输入缓冲区溢出

Kafka消息保证不丢失和重复消费问题

React Uncaught ReferenceError:未定义缓冲区

我可以避免将模板缓冲区从 FBO 传送到后台缓冲区吗?

Redis缓冲区设置

是否应该避免嵌套锁定请求?